package com.wei.czz.framework.admin.manager;

import com.wei.czz.common.constant.Constant;
import com.wei.czz.common.constant.RedisConstant;
import com.wei.czz.common.constant.EntityConstant;
import com.wei.czz.common.dto.admin.DeptUserDto;
import com.wei.czz.common.dto.admin.DeptUserFlowDto;
import com.wei.czz.common.dto.admin.UserDto;
import com.wei.czz.common.dto.admin.user.UserPageEnumDto;
import com.wei.czz.common.dto.common.NameValue;
import com.wei.czz.common.dto.common.UploadDto;
import com.wei.czz.common.easyexcel.listener.ObjectUploadListener;
import com.wei.czz.common.enums.CommonEnum;
import com.wei.czz.common.enums.admin.deptUser.DeptUserMoveModeEnum;
import com.wei.czz.common.enums.ResultEnum;
import com.wei.czz.common.enums.admin.user.UserContactFlowEnum;
import com.wei.czz.common.enums.admin.user.RequestChannelEnum;
import com.wei.czz.common.enums.admin.userRole.RelationModeEnum;
import com.wei.czz.common.enums.common.dict.DictEnum;
import com.wei.czz.common.enums.common.importTask.ImportTaskTypeEnum;
import com.wei.czz.common.enums.index.validateCode.ValidateCodeTypeEnum;
import com.wei.czz.common.enums.rabbitMQ.MqEnum;
import com.wei.czz.common.exception.CzzException;
import com.wei.czz.common.po.UserPo;
import com.wei.czz.common.po.admin.userRole.UserRolePo;
import com.wei.czz.common.tool.PageDto;
import com.wei.czz.common.utils.*;
import com.wei.czz.common.vo.admin.deptUser.DeptUserJoinVo;
import com.wei.czz.common.vo.admin.user.UserUploadVo;
import com.wei.czz.framework.admin.entity.*;
import com.wei.czz.framework.admin.service.*;
import com.wei.czz.framework.common.handler.ThrottleHandler;
import com.wei.czz.framework.common.helper.*;
import com.wei.czz.framework.common.handler.redis.RedisHashHandler;
import com.wei.czz.framework.common.handler.redis.RedisHandler;
import com.wei.czz.framework.common.handler.redis.RedisStringHandler;
import com.wei.czz.common.vo.admin.DeptUserFlowVo;
import com.wei.czz.common.vo.admin.user.UserVo;
import com.wei.czz.common.vo.admin.user.UpdatePasswordVo;
import com.wei.czz.common.vo.admin.deptUser.DeptUserFormVo;
import com.wei.czz.framework.admin.helper.DeptHelper;
import com.wei.czz.framework.admin.helper.UserHelper;
import com.wei.czz.framework.common.service.*;
import com.wei.czz.framework.common.wrapper.DictWrapper;
import com.wei.czz.framework.security.entity.SecurityUser;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2023-12-07 14:26:32
 * className: UserManager
 * version: 1.0
 * description:
 */
@Component
@AllArgsConstructor
public class UserManager {

    private static final Logger log = LoggerFactory.getLogger(UserManager.class);

    private final UserService userService;

    private final UserLoginService userLoginService;

    private final UserLoginFlowService userLoginFlowService;

    private final UserAccessTokenService userAccessTokenService;

    private final MenuService menuService;

    private final DeptService deptService;

    private final DeptUserService deptUserService;

    private final DeptRoleService deptRoleService;

    private final DeptUserFlowService deptUserFlowService;

    private final RoleService roleService;

    private final UserRoleService userRoleService;

    private final UserContactFlowService userContactFlowService;

    private final UserSequenceService userSequenceService;

    private final HistoryPasswordService historyPasswordService;

    private final ValidateCodeService validateCodeService;

    private final AsyncService asyncService;

    private final TransactionService transactionService;

    private final ImportTaskHelper importTaskHelper;

    private final RedisHashHandler redisHashHandler;

    private final RedisStringHandler redisStringHandler;

    private final RedisHandler redisHandler;

    private final RedissonClient redissonClient;

    private final AesService aesService;

    private final UserHelper userHelper;

    private final DeptHelper deptHelper;

    private final ThrottleHandler throttleHandler;

    private final CacheHelper cacheHelper;

    private final RabbitHelper rabbitHelper;

    private final DictWrapper dictWrapper;

    @Transactional
    public void saveUser(UserVo userVo) {
        // 获取操作用户
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        // 手机号加密
        String phone = Optional.ofNullable(userVo.getPhone())
                .filter(StringUtils::isNotBlank)
                .map(aesService::encryptToHex)
                .orElse(StringUtils.EMPTY);
        // 邮箱号加密
        String email = Optional.ofNullable(userVo.getEmail())
                .filter(StringUtils::isNotBlank)
                .map(aesService::encryptToHex)
                .orElse(StringUtils.EMPTY);
        String loginName= Optional.ofNullable(userVo.getLoginName()).orElse(StringUtils.EMPTY);

        /*
            检查用户是否允许添加
         */
        userService.checkLoginInfo(null, phone, email, userVo.getLoginName());

        /*
            查询用户默认头像配置
         */
        String avatar = dictWrapper.getOneDict(DictEnum.DEFAULT_USER_AVATAR).getValue();

        // 生成盐
        String salt = RandomNumUtils.getRandomSizeNum(20);

        /*
            生产一个用户编号
         */
        Long userNo = userSequenceService.get();

        /*
            保存用户
         */
        UserEntity user = new UserEntity();
        user.setUserNo(userHelper.fullUserNo(userNo))
            .setUsername(userVo.getUsername())
            .setAvatar(avatar)
            .setPhone(phone)
            .setEmail(email)
            .setLoginName(loginName)
            .setPassword(ShaUtils.encodeSha256(Constant.DEFAULT_PASSWORD, salt))
            .setSalt(salt)
            .setStatus(CommonEnum.ZERO.getValue())
            .setDeleteStatus(CommonEnum.ZERO.getValue())
            .setUpdateTime(date)
            .setUpdateUser(StringUtils.EMPTY)
            .setUpdateUserId(CommonEnum.ZERO.getLongValue())
            .setCreateTime(date)
            .setCreateUser(userPo.getUsername())
            .setCreateUserId(userPo.getUserId());
        userService.saveOrEdit(user);

        Long userId = user.getUserId();

        /*
            保存用户与部门关联关系
         */
        DeptUserEntity deptUser = new DeptUserEntity();
        deptUser.setUserId(userId)
                .setDeptId(userVo.getDeptId())
                .setMasterStatus(CommonEnum.ZERO.getValue())
                .setLeaderStatus(CommonEnum.ONE.getValue())
                .setDeleteStatus(CommonEnum.ZERO.getValue())
                .setUpdateTime(date)
                .setUpdateUser(StringUtils.EMPTY)
                .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                .setCreateTime(date)
                .setCreateUser(userPo.getUsername())
                .setCreateUserId(userPo.getUserId());
        deptUserService.saveOrEdit(deptUser);

        asyncService.execute(() -> {
            /*
                保存用户关联部门流水
             */
            DeptUserFlowEntity userDeptFlow = new DeptUserFlowEntity();
            userDeptFlow.setUserId(user.getUserId())
                    .setPreDeptId(CommonEnum.ZERO.getLongValue())
                    .setNextDeptId(userVo.getDeptId())
                    .setMoveMode(CommonEnum.MINUS_ONE.getValue())
                    .setMoveRemark(StringUtils.EMPTY)
                    .setDeleteStatus(CommonEnum.ZERO.getValue())
                    .setUpdateTime(date)
                    .setUpdateUser(StringUtils.EMPTY)
                    .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                    .setCreateTime(date)
                    .setCreateUser(userPo.getUsername())
                    .setCreateUserId(userPo.getUserId());
            deptUserFlowService.saveOrEdit(userDeptFlow);

            /*
                保存用户联系方式流水
             */
            List<UserContactFlowEntity> userContactFlowList = new ArrayList<>();
            if (StringUtils.isNotBlank(phone)) {
                UserContactFlowEntity userContactFlow = new UserContactFlowEntity();
                userContactFlow.setUserId(userId)
                        .setType(UserContactFlowEnum.PHONE.getValue())
                        .setMode(UserContactFlowEnum.BIND.getValue())
                        .setContact(phone)
                        .setDeleteFlag(CommonEnum.ZERO.getValue())
                        .setDeleteTime(date)
                        .setCreateTime(date)
                        .setCreateUser(userPo.getUserId());
                userContactFlowList.add(userContactFlow);
            }
            if (StringUtils.isNotBlank(email)) {
                UserContactFlowEntity userContactFlow = new UserContactFlowEntity();
                userContactFlow.setUserId(userId)
                        .setType(UserContactFlowEnum.EMAIL.getValue())
                        .setMode(UserContactFlowEnum.BIND.getValue())
                        .setContact(email)
                        .setDeleteFlag(CommonEnum.ZERO.getValue())
                        .setDeleteTime(date)
                        .setCreateTime(date)
                        .setCreateUser(userPo.getUserId());
                userContactFlowList.add(userContactFlow);
            }
            if (!userContactFlowList.isEmpty()) {
                userContactFlowService.batchSave(userContactFlowList);
            }

            /*
                更新用户关联序号
             */
            userSequenceService.update(userNo, userId);
        });

        // 发送mq消息
        rabbitHelper.send(MqEnum.DEPT_USER, Collections.singletonList(userId));

        /*
            操作缓存
         */
        // 删除所有系统用户相关的临时缓存数据
        this.deleteUserCache(Collections.emptyList());

    }

    public UploadDto<UserUploadVo> uploadUser(ObjectUploadListener<UserUploadVo> objectUploadListener) {
        // 获取操作用户
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        ImportTaskTypeEnum importTaskTypeEnum = ImportTaskTypeEnum.USER;

        // 解析成功列表
        List<UserUploadVo> successList = objectUploadListener.getSuccessList();
        // 解析失败列表
        List<UserUploadVo> failList = objectUploadListener.getFailList();

        /*
            判断是否有可导入数据
         */
        if (successList.isEmpty()) {
            // 没有解析成功数据，直接返回
            return importTaskHelper.buildSyncUploadDto(importTaskTypeEnum, successList, failList, UserUploadVo.class);
        }
        List<Long> deptIdList = new ArrayList<>();
        List<String> deptNameList = new ArrayList<>();

        Pattern idPattern = Pattern.compile("^\\d+$");

        Iterator<UserUploadVo> iterator = successList.iterator();
        while (iterator.hasNext()) {
            UserUploadVo userUploadVo = iterator.next();

            String dept = userUploadVo.getDept();
            if (idPattern.matcher(dept).matches()) {
                try {
                    deptIdList.add(Long.parseLong(dept));
                } catch (NumberFormatException e) {
                    log.error("部门主键解析异常。serial={} dept={} message={}", userUploadVo.getSerial(), dept, e.getMessage());
                    userUploadVo.setErrorMessage("部门主键解析失败");
                    failList.add(userUploadVo);
                    iterator.remove();
                }
            } else {
                deptNameList.add(dept);
            }
        }

        Map<String, Long> deptMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(deptIdList)) {
            /*
                获取部门列表
             */
            List<DeptEntity> deptList = deptService.getList(deptIdList);
            for (DeptEntity dept : deptList) {
                deptMap.put(dept.getId().toString(), dept.getId());
            }
        }
        if (!CollectionUtils.isEmpty(deptNameList)) {
            /*
                获取部门列表
             */
            List<DeptEntity> deptList = deptService.findListByName(deptNameList);
            for (DeptEntity dept : deptList) {
                deptMap.put(dept.getName(), dept.getId());
            }
        }

        /*
            查询用户默认头像配置
         */
        String avatar = dictWrapper.getOneDict(DictEnum.DEFAULT_USER_AVATAR).getValue();

        /*
            再次遍历，构造数据
         */
        List<UserEntity> userList = new ArrayList<>();
        List<DeptUserEntity> deptUserList = new ArrayList<>();
        List<DeptUserFlowEntity> deptUserFlowList = new ArrayList<>();
        List<UserContactFlowEntity> userContactFlowList = new ArrayList<>();
        List<UserSequenceEntity> userSequenceList = new ArrayList<>();

        iterator = successList.iterator();
        while (iterator.hasNext()) {
            UserUploadVo userUploadVo = iterator.next();

            if (!deptMap.containsKey(userUploadVo.getDept())) {
                userUploadVo.setErrorMessage("用户所属部门不存在，请确认");
                failList.add(userUploadVo);
                iterator.remove();
            }

            // 手机号加密
            String phone = Optional.ofNullable(userUploadVo.getPhone())
                    .filter(StringUtils::isNotBlank)
                    .map(aesService::encryptToHex)
                    .orElse(StringUtils.EMPTY);
            // 邮箱号加密
            String email = Optional.ofNullable(userUploadVo.getEmail())
                    .filter(StringUtils::isNotBlank)
                    .map(aesService::encryptToHex)
                    .orElse(StringUtils.EMPTY);

            // 生成盐
            String salt = RandomNumUtils.getRandomSizeNum(20);

            /*
                保存用户
             */
            UserEntity user = new UserEntity();
            user.setUsername(userUploadVo.getUsername())
                    .setAvatar(avatar)
                    .setPhone(phone)
                    .setEmail(email)
                    .setLoginName(StringUtils.EMPTY)
                    .setPassword(ShaUtils.encodeSha256(Constant.DEFAULT_PASSWORD, salt))
                    .setSalt(salt)
                    .setStatus(CommonEnum.ZERO.getValue())
                    .setDeleteStatus(CommonEnum.ZERO.getValue())
                    .setUpdateTime(date)
                    .setUpdateUser(StringUtils.EMPTY)
                    .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                    .setCreateTime(date)
                    .setCreateUser(userPo.getUsername())
                    .setCreateUserId(userPo.getUserId());
            userList.add(user);

        }

        /*
            生成导入记录
         */
        UploadDto<UserUploadVo> uploadDto = importTaskHelper.buildSyncUploadDto(importTaskTypeEnum, successList,
                failList, UserUploadVo.class);

        int successSize = successList.size();
        if (successSize == 0) {
            log.info("映射成功数据为空");
            return uploadDto;
        }

        transactionService.execute(() -> {
            /*
                生产用户编号
             */
            List<Long> userNoList = userSequenceService.batchGet(successSize);

            for (int i = 0; i < successSize; i++) {
                UserUploadVo userUploadVo = successList.get(i);
                UserEntity user = userList.get(i);
                Long userNo = userNoList.get(i);

                Long deptId = deptMap.get(userUploadVo.getDept());
                if (Objects.isNull(deptId)) {
                    log.error("找不到用户所属部门。dept={} deptMap={}", userUploadVo.getDept(), deptMap);
                    continue;
                }

                user.setUserNo(userHelper.fullUserNo(userNo))
                        .setLoginName(user.getUserNo());

                UserSequenceEntity userSequence = new UserSequenceEntity();
                userSequence.setId(userNo)
                        .setUpdateTime(date)
                        .setUpdateUser(userPo.getUsername())
                        .setUpdateUserId(userPo.getUserId());
                userSequenceList.add(userSequence);
            }

            /*
                批量保存用户
             */
            userService.batchSave(userList);
        });


        List<Long> userIdList = new ArrayList<>();
        for (int i = 0; i < successSize; i++) {
            UserUploadVo userUploadVo = successList.get(i);
            UserEntity user = userList.get(i);
            UserSequenceEntity userSequence = userSequenceList.get(i);

            Long deptId = deptMap.get(userUploadVo.getDept());
            if (Objects.isNull(deptId)) {
                log.error("找不到用户所属部门。dept={} deptMap={}", userUploadVo.getDept(), deptMap);
                continue;
            }
            // 记录用户主键
            userIdList.add(user.getUserId());
            // 设置使用编号的用户
            userSequence.setUseUserId(user.getUserId());

            /*
                用户与部门关联关系
             */
            DeptUserEntity deptUser = new DeptUserEntity();
            deptUser.setUserId(user.getUserId())
                    .setDeptId(deptId)
                    .setMasterStatus(CommonEnum.ZERO.getValue())
                    .setLeaderStatus(CommonEnum.ONE.getValue())
                    .setDeleteStatus(CommonEnum.ZERO.getValue())
                    .setUpdateTime(date)
                    .setUpdateUser(StringUtils.EMPTY)
                    .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                    .setCreateTime(date)
                    .setCreateUser(userPo.getUsername())
                    .setCreateUserId(userPo.getUserId());
            deptUserList.add(deptUser);

            /*
                用户关联部门流水
             */
            DeptUserFlowEntity deptUserFlow = new DeptUserFlowEntity();
            deptUserFlow.setUserId(user.getUserId())
                    .setPreDeptId(CommonEnum.ZERO.getLongValue())
                    .setNextDeptId(deptId)
                    .setMoveMode(CommonEnum.MINUS_ONE.getValue())
                    .setMoveRemark(StringUtils.EMPTY)
                    .setDeleteStatus(CommonEnum.ZERO.getValue())
                    .setUpdateTime(date)
                    .setUpdateUser(StringUtils.EMPTY)
                    .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                    .setCreateTime(date)
                    .setCreateUser(userPo.getUsername())
                    .setCreateUserId(userPo.getUserId());
            deptUserFlowList.add(deptUserFlow);

            /*
                保存用户联系方式流水
             */
            if (StringUtils.isNotBlank(user.getPhone())) {
                UserContactFlowEntity userContactFlow = new UserContactFlowEntity();
                userContactFlow.setUserId(user.getUserId())
                        .setType(UserContactFlowEnum.PHONE.getValue())
                        .setMode(UserContactFlowEnum.BIND.getValue())
                        .setContact(user.getPhone())
                        .setDeleteFlag(CommonEnum.ZERO.getValue())
                        .setDeleteTime(date)
                        .setCreateTime(date)
                        .setCreateUser(userPo.getUserId());
                userContactFlowList.add(userContactFlow);
            }
            if (StringUtils.isNotBlank(user.getEmail())) {
                UserContactFlowEntity userContactFlow = new UserContactFlowEntity();
                userContactFlow.setUserId(user.getUserId())
                        .setType(UserContactFlowEnum.EMAIL.getValue())
                        .setMode(UserContactFlowEnum.BIND.getValue())
                        .setContact(user.getEmail())
                        .setDeleteFlag(CommonEnum.ZERO.getValue())
                        .setDeleteTime(date)
                        .setCreateTime(date)
                        .setCreateUser(userPo.getUserId());
                userContactFlowList.add(userContactFlow);
            }
        }

        asyncService.execute(() -> {
            /*
                批量保存部门用户
             */
            if (!deptUserList.isEmpty()) {
                deptUserService.batchSave(deptUserList);
            }

            /*
                批量保存部门关联关联用户流水
             */
            if (!deptUserFlowList.isEmpty()) {
                deptUserFlowService.batchSave(deptUserFlowList);
            }

            /*
                批量保存用户联系方式记录
             */
            if (!userContactFlowList.isEmpty()) {
                userContactFlowService.batchSave(userContactFlowList);
            }

            /*
                批量更新用户关联序号
             */
            if (!userSequenceList.isEmpty()) {
                userSequenceService.batchUpdate(userSequenceList);
            }
        });

        // 发送mq消息
        rabbitHelper.send(MqEnum.DEPT_USER, userIdList);

        /*
            操作缓存
         */
        // 删除所有系统用户相关的临时缓存数据
        this.deleteUserCache(Collections.emptyList());

        return uploadDto;
    }

    public void cacheUser(List<Long> userIdList) {

        /*
            获取用户
         */
        List<UserEntity> userList = userService.getList(userIdList);
        if (userList.isEmpty()) {
            return;
        }

        Map<String, UserEntity> userMap = new HashMap<>();
        for (UserEntity user : userList) {
            user.setPassword(null);
            userMap.put(user.getUserId().toString(), user);
        }
        // 操作Redis缓存，批量新增用户缓存信息
        redisHashHandler.putAll(CacheKeyUtils.getRedisHashKey(EntityConstant.USER), userMap);

    }

    public List<DeptUserDto> getDeptUserList(Long deptId) {

        /*
            获取部门
         */
        DeptEntity dept = deptService.get(deptId);

        // 构造子部门数据存储的父级部门路径值
        String deptPath = dept.getParentPath() + deptId + Constant.SPLIT;
        // 根据父级部门路径查询所有子部门主键数据
        List<DeptEntity> deptList = deptService.getChildrenList(deptPath);

        List<Long> deptIdList = new ArrayList<>(deptList.size() + 1);
        Map<Long, String> deptMap = new HashMap<>();
        for (DeptEntity deptEntity : deptList) {
            deptIdList.add(deptEntity.getId());
            deptMap.put(deptEntity.getId(), deptEntity.getName());
        }
        deptIdList.add(deptId);
        deptMap.put(dept.getId(), dept.getName());

        /*
            获取部门关联用户
         */
        List<DeptUserEntity> deptUserList = deptUserService.findList(deptIdList, null);
        // 收集用户主键
        List<Long> userIdList = new ArrayList<>();
        Map<Long, List<DeptUserEntity>> deptUserMap = new HashMap<>();
        for (DeptUserEntity deptUser : deptUserList) {
            // 收集用户主键
            userIdList.add(deptUser.getUserId());

            List<DeptUserEntity> list = deptUserMap.computeIfAbsent(deptUser.getUserId(), k -> new ArrayList<>());
            // 收集用户关联部门
            list.add(deptUser);
        }

        /*
            获取用户
         */
        List<UserEntity> userList = userService.getList(userIdList);

        List<DeptUserDto> deptUserDtoList = new ArrayList<>(deptUserList.size());
        for (UserEntity user : userList) {
            deptUserList = deptUserMap.get(user.getUserId());
            if (CollectionUtils.isEmpty(deptUserList)) {
                continue;
            }
            for (DeptUserEntity deptUser : deptUserList) {
                // 映射
                DeptUserDto deptUserDto = new DeptUserDto();
                deptUserDto.setId(deptUser.getId().toString())
                        .setDeptName(deptMap.get(deptUser.getDeptId()))
                        .setUserId(user.getUserId().toString())
                        .setUsername(user.getUsername())
                        .setStatus(user.getStatus())
                        .setStatusName(CommonEnum.getStatusName(user.getStatus()))
                        .setLeaderStatus(deptUser.getLeaderStatus())
                        .setLeaderStatusName(
                                CommonEnum.ZERO.getValue().equals(deptUser.getLeaderStatus()) ? "是" : "否"
                        )
                        .setCreateTime(deptUser.getCreateTime())
                        .setCreateUser(deptUser.getCreateUser());

                deptUserDtoList.add(deptUserDto);
            }
        }
        return deptUserDtoList;
    }

    public PageDto<UserDto> getDeptUserPageList(DeptUserFormVo deptUserFormVo) {
        // 获取请求用户
        UserPo userPo = SecurityUtils.getUser();

        /*
            缓存用户请求参数
         */
        String cacheKey = CacheKeyUtils.getDeptUserParamCacheKey(deptUserFormVo.getDeptId());
        cacheHelper.cache(cacheKey, deptUserFormVo);

        // 判断请求用户是否超级管理员
        boolean superManager = userHelper.isSuperManager();

        List<Long> deptIdList = Collections.singletonList(deptUserFormVo.getDeptId());
        if (!superManager) {
            // 不是超级管理员，则需要判断‘操作用户’是否拥有该部门管理权限
            List<Long> manageDeptIdList = deptHelper.getManageDeptIdList(userPo.getUserId());
            if (!manageDeptIdList.contains(deptUserFormVo.getDeptId())) {
                log.warn("【{}】用户（{}）没有该部门管理权限，不能获取部门关联用户", userPo.getUserId(), userPo.getUsername());
                throw new CzzException(ResultEnum.ILLEGAL_FAIL.getCode(), "很抱歉，您没有部门的管理权限");
            }
        }
        deptUserFormVo.setDeptIdList(deptIdList);

        if (StringUtils.isNotBlank(deptUserFormVo.getContact())) {
            // 联系方式加密
            String contact = aesService.encryptToHex(deptUserFormVo.getContact());

            if (RegexUtils.isPhone(deptUserFormVo.getContact())) {
                deptUserFormVo.setPhone(contact);
            }
            if (RegexUtils.isEmail(deptUserFormVo.getContact())) {
                deptUserFormVo.setEmail(contact);
            }
            // 入参置空
            deptUserFormVo.setContact(null);
        }

        // 获取并返回
        return this.getPageList(deptUserFormVo);
    }

    public PageDto<UserDto> getUserPageList(DeptUserFormVo deptUserFormVo) {
        // 获取请求用户
        UserPo userPo = SecurityUtils.getUser();

        /*
            缓存用户请求参数
         */
        String cacheKey = CacheKeyUtils.getParamCacheKey(EntityConstant.USER);
        cacheHelper.cache(cacheKey, deptUserFormVo);

        // 判断请求用户是否超级管理员
        boolean superManager = userHelper.isSuperManager();

        List<Long> deptIdList = Collections.emptyList();
        if (Objects.isNull(deptUserFormVo.getDeptId())) {
            if (!superManager) {
                // 不是超级管理员，则只能查询管理部门及其子孙部门的用户
                List<Long> manageDeptIdList = deptHelper.getManageDeptIdList(userPo.getUserId());
                if (manageDeptIdList.isEmpty()) {
                    log.warn("【{}】用户（{}）没有直接管理的部门，不能获取用户", userPo.getUserId(), userPo.getUsername());
                    throw new CzzException(ResultEnum.ILLEGAL_FAIL.getCode(), "很抱歉，您没有用户的管理权限");
                }
                /*
                    获取部门及其子部门
                 */
                List<DeptEntity> deptList = deptService.findList(manageDeptIdList);
                // 收集部门主键
                deptIdList = CopyUtils.mapList(deptList, DeptEntity::getId);
            }
        } else {
            if (!superManager) {
                // 不是超级管理员，则需要判断‘操作用户’是否拥有该部门管理权限
                List<Long> manageDeptIdList = deptHelper.getManageDeptIdList(userPo.getUserId());
                if (!manageDeptIdList.contains(deptUserFormVo.getDeptId())) {
                    log.warn("【{}】用户（{}）没有该部门管理权限，不能获取用户", userPo.getUserId(), userPo.getUsername());
                    throw new CzzException(ResultEnum.ILLEGAL_FAIL.getCode(), "很抱歉，您没有部门的管理权限");
                }
            }
            /*
                查询子部门主键
             */
            deptIdList = deptService.getChildrenIdList(deptUserFormVo.getDeptId());
            deptIdList.add(deptUserFormVo.getDeptId());
        }
        deptUserFormVo.setDeptIdList(deptIdList);

        if (StringUtils.isNotBlank(deptUserFormVo.getContact())) {
            // 联系方式加密
            String contact = aesService.encryptToHex(deptUserFormVo.getContact());

            if (RegexUtils.isPhone(deptUserFormVo.getContact())) {
                deptUserFormVo.setPhone(contact);
            }
            if (RegexUtils.isEmail(deptUserFormVo.getContact())) {
                deptUserFormVo.setEmail(contact);
            }
            // 入参置空
            deptUserFormVo.setContact(null);
        }

        // 获取并返回
        return this.getPageList(deptUserFormVo);
    }

    public UserPageEnumDto getUserPageEnum() {
        // 获取请求用户主键
        Long optUserId = SecurityUtils.getUserId();

        /*
            获取用户请求参数
         */
        String cacheKey = CacheKeyUtils.getParamCacheKey(EntityConstant.USER);
        DeptUserFormVo deptUserFormVo = cacheHelper.get(cacheKey, DeptUserFormVo.class);

        List<NameValue<Integer>> leaderStatusList = new ArrayList<>(2);
        leaderStatusList.add(new NameValue<>("是", CommonEnum.ZERO.getValue()));
        leaderStatusList.add(new NameValue<>("否", CommonEnum.ONE.getValue()));

        UserPageEnumDto userPageEnumDto = new UserPageEnumDto();
        userPageEnumDto.setStatusList(CommonEnum.getStatusList())
                .setDeptUserFormVo(deptUserFormVo)
                .setLeaderStatusList(leaderStatusList);
        return userPageEnumDto;
    }

    public UserDto getUserView(Long userId) {
        /*
            获取用户
         */
        UserEntity user = userHelper.get(userId);

        /*
            获取用户关联部门
         */
        List<DeptUserEntity> deptUSerList = deptUserService.findList(null, Collections.singletonList(userId));
        // 收集
        List<Long> deptIdList = CopyUtils.mapList(deptUSerList, DeptUserEntity::getDeptId);

        /*
            获取部门名称映射
         */
        Map<Long, String> deptNameMap = deptService.getDeptNameMap(deptIdList, Function.identity());

        StringBuilder sb = new StringBuilder();
        for (Long deptId : deptIdList) {
            String deptName = deptNameMap.get(deptId);
            if (StringUtils.isNotBlank(deptName)) {
                sb.append(deptName).append('、');
            }
        }
        if (sb.length() > 1) {
            sb.deleteCharAt(sb.length() - 1);
        }

        /*
            获取创建用户名称
         */
        Map<Long, String> userNameMap = userService.getNameMap(Collections.singleton(user.getCreateUserId()),
                Function.identity());
        /*
            获取用户关联角色数据
         */
        List<UserRolePo> roleList = roleService.findList(userId, null);
        // 收集角色名称
        List<String> roleNameList = roleList.stream().map(UserRolePo::getRoleName).collect(Collectors.toList());

        UserDto userDto = new UserDto();
        // 设置用户名称、手机号、邮箱号、登录别名、用户状态和关联的角色id属性值
        userDto.setDeptNames(sb.toString())
                .setUsername(user.getUsername())
                .setPhone(user.getPhone())
                .setEmail(user.getEmail())
                .setLoginName(user.getLoginName())
                .setStatus(user.getStatus())
                .setCreateTime(user.getCreateTime())
                .setCreateUser(userNameMap.get(user.getCreateUserId()))
                .setRoleList(roleNameList);
        return userDto;
    }

    public UserDto getSelf() {
        // 获取请求用户
        UserPo userPo = SecurityUtils.getUser();

        String phone = StringUtils.EMPTY;
        if (StringUtils.isNotBlank(userPo.getPhone())) {
            phone = aesService.decodeHex(userPo.getPhone());
        }
        String email = StringUtils.EMPTY;
        if (StringUtils.isNotBlank(userPo.getEmail())) {
            email = aesService.decodeHex(userPo.getEmail());
        }

        UserDto userDto = new UserDto();
        userDto.setUsername(userPo.getUsername())
                .setAvatar(userPo.getAvatar())
                .setPhone(phone)
                .setEmail(email)
                .setLoginName(userPo.getLoginName());
        return userDto;
    }

    public Set<String> getPermitSet() {
        // 获取请求用户
        SecurityUser securityUser = SecurityUtils.getSecurityUser();
        if (!securityUser.getSuperManager()) {
            // 不是超级管理员，直接返回用户登录对象存储的权限集合
            return securityUser.getPermitSet();
        }

        // 超级管理员，获取所有菜单
        List<MenuEntity> menuList = menuService.getMenuList(CommonEnum.ZERO.getValue());

        // 收集权限
        return menuList.stream()
                .map(MenuEntity::getPermit)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toSet());
    }


    public PageDto<DeptUserFlowDto> getUserDeptFlowPageList(Long userId, Integer page, Integer limit) {
        /*
            分页查询用户切换部门流水
         */
        PageDto<DeptUserFlowEntity> pageDto = deptUserFlowService.getPageList(userId, page, limit);

        if (pageDto.isEmpty()) {
            log.info("分页查询结果为空");
            return pageDto.rebuild();
        }

        List<DeptUserFlowEntity> userDeptFlowList = pageDto.getList();

        Set<Long> deptIdSet = new HashSet<>();
        for (DeptUserFlowEntity userDeptFlow : userDeptFlowList) {
            deptIdSet.add(userDeptFlow.getPreDeptId());
            deptIdSet.add(userDeptFlow.getNextDeptId());
        }

        /*
            获取部门名称映射
         */
        Map<Long, String> deptNameMap = deptService.getDeptNameMap(deptIdSet, Function.identity());

        List<DeptUserFlowDto> deptUserFlowDtoList = new ArrayList<>(userDeptFlowList.size());
        for (DeptUserFlowEntity userDeptFlow : userDeptFlowList) {
            DeptUserFlowDto deptUserFlowDto = new DeptUserFlowDto();
            deptUserFlowDto.setPreDeptName(deptNameMap.get(userDeptFlow.getPreDeptId()));
            deptUserFlowDto.setNextDeptName(deptNameMap.get(userDeptFlow.getNextDeptId()));
            deptUserFlowDto.setMoveMode(userDeptFlow.getMoveMode());
            deptUserFlowDto.setMoveModeName(DeptUserMoveModeEnum.getName(userDeptFlow.getMoveMode()));
            deptUserFlowDto.setMoveRemark(userDeptFlow.getMoveRemark());
            deptUserFlowDto.setCreateTime(userDeptFlow.getCreateTime());
            deptUserFlowDto.setCreateUser(userDeptFlow.getCreateUser());
            deptUserFlowDtoList.add(deptUserFlowDto);
        }
        // 封装返回
        return pageDto.rebuild(deptUserFlowDtoList);
    }

    @Transactional
    public void unbindPhone() {
        // 获取操作用户
        UserPo userPo = SecurityUtils.getUser();
        log.info("用户【{}】手机号解除绑定", userPo.getUserId());

        /*
            判断用户是否绑定手机号
         */
        UserEntity user = userHelper.get(userPo.getUserId());
        if (StringUtils.isBlank(user.getPhone())) {
            log.info("用户未绑定手机号");
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "您未绑定手机号，无法解绑");
        }

        /*
            修改用户手机号
         */
        UserEntity updateUser = new UserEntity();
        updateUser.setUserId(userPo.getUserId())
            .setPhone(StringUtils.EMPTY)
            .setUpdateTime(new Date())
            .setUpdateUser(userPo.getUsername())
            .setUpdateUserId(userPo.getUserId());
        // 修改用户基础数据
        userService.saveOrEdit(updateUser);

        /*
            添加用户联系方式变更流水
         */
        userContactFlowService.saveUserContactFlow(userPo.getUserId(), UserContactFlowEnum.PHONE.getValue(),
                UserContactFlowEnum.UNBIND.getValue(), user.getPhone());
    }

    public void unbindEmail() {
        UserPo userPo = SecurityUtils.getUser();
        log.info("用户【{}】邮箱号解除绑定", userPo.getUserId());

        /*
            判断用户是否绑定邮箱
         */
        UserEntity user = userHelper.get(userPo.getUserId());
        if (StringUtils.isBlank(user.getEmail())) {
            log.info("用户未绑定邮箱");
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "您未绑定邮箱，无法解绑");
        }

        /*
            修改用户
         */
        UserEntity updateUser = new UserEntity();
        updateUser.setUserId(userPo.getUserId())
            .setEmail(StringUtils.EMPTY)
            .setUpdateTime(new Date())
            .setUpdateUser(userPo.getUsername())
            .setUpdateUserId(userPo.getUserId());
        // 修改用户基础数据
        userService.saveOrEdit(updateUser);

        /*
            添加用户联系方式变更流水
         */
        userContactFlowService.saveUserContactFlow(userPo.getUserId(), UserContactFlowEnum.EMAIL.getValue(),
                UserContactFlowEnum.UNBIND.getValue(), user.getEmail());
    }

    @Transactional
    public void userLogout(RequestChannelEnum requestChannelEnum) {
        // 获取操作用户
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        /*
            获取用户登录记录
         */
        List<UserLoginEntity> userLoginList = userLoginService.findList(userPo.getUserId(),
                requestChannelEnum.getValue());
        if (userLoginList.isEmpty()) {
            log.info("用户登录记录不存在");
            throw new CzzException(ResultEnum.ILLEGAL_FAIL);
        }
        UserLoginEntity userLogin = userLoginList.get(userLoginList.size() - 1);
        log.info("登录记录。{}", userLogin);
        if (!CommonEnum.ZERO.getValue().equals(userLogin.getStatus())) {
            log.info("用户不是登陆中");
            throw new CzzException(ResultEnum.ILLEGAL_FAIL);
        }

        /*
            获取用户登录流水
         */
        List<UserLoginFlowEntity> userLoginFlowList = userLoginFlowService.findList(userPo.getUserId(),
                requestChannelEnum.getValue());

        /*
            更新用户登录记录
         */
        UserLoginEntity updateUserLogin = new UserLoginEntity();
        updateUserLogin.setId(userLogin.getId())
                .setType(CommonEnum.MINUS_ONE.getValue())
                .setLoginIp(StringUtils.EMPTY)
                .setLoginAddress(StringUtils.EMPTY)
                .setLoginTime(CommonEnum.ZERO.getLongValue())
                .setExpireTime(CommonEnum.ZERO.getLongValue())
                .setStatus(CommonEnum.ONE.getValue())
                .setUpdateTime(date)
                .setUpdateUser(userPo.getUsername())
                .setUpdateUserId(userPo.getUserId());
        userLoginService.saveOrEdit(updateUserLogin);

        List<UserLoginFlowEntity> updateList = new ArrayList<>(userLoginFlowList.size());
        for (UserLoginFlowEntity userLoginFlow : userLoginFlowList) {
            UserLoginFlowEntity updateUserLoginFlow = new UserLoginFlowEntity();
            updateUserLoginFlow.setId(userLoginFlow.getId())
                    .setLogoutTime(date.getTime())
                    .setUpdateTime(date)
                    .setUpdateUser(userPo.getUsername())
                    .setUpdateUserId(userPo.getUserId());
            updateList.add(updateUserLoginFlow);
        }
        if (!updateList.isEmpty()) {
            userLoginFlowService.batchUpdate(updateList);
        }

        /*
            清理用户令牌
         */
        userAccessTokenService.clearOther(userPo.getUserId(), requestChannelEnum.getValue(), null);

        // 操作Redis缓存，删除用户登录信息
        String cacheKey = CacheKeyUtils.getSecurityUserKey(userPo.getUserId());
        redisHandler.delete(cacheKey);

        // 操作Redis缓存，删除户登录过期时间
//        redisZSetHelper.remove(RedisConstant.OVER_TIME_ZSET, userId);
    }

    public void kickLogin(List<UserLoginEntity> userLoginList) {
        // 获取操作用户
        Long optUserId = CommonEnum.ZERO.getLongValue();
        String optUsername = StringUtils.EMPTY;
        Date date = new Date();

        try {
            UserPo userPo = SecurityUtils.getUser();

            optUserId = userPo.getUserId();
            optUsername = userPo.getUsername();
        } catch (Exception e) {
            log.info("用户踢出登录，没有登录用户。");
        }
        // 收集用户主键
        List<Long> userIdList = CopyUtils.mapList(userLoginList, UserLoginEntity::getUserId);

        /*
            获取用户登录记录
         */
        List<UserLoginEntity> userExpireLoginList = userLoginService.findList(userIdList);
        Function<UserLoginEntity, String> keyFunction =
                userLogin -> userLogin.getUserId() + Constant.SPLIT + userLogin.getChannel();
        // 列表 转 映射
        Map<String, UserLoginEntity> userLoginMap = CopyUtils.listToMap(userExpireLoginList, keyFunction,
                Function.identity());

        /*
            更新用户登录
         */
        List<UserLoginEntity> updateUserLoginList = new ArrayList<>(userLoginList.size());

        Iterator<UserLoginEntity> userLoginIterator = userLoginList.iterator();
        while (userLoginIterator.hasNext()) {
            UserLoginEntity userLogin = userLoginIterator.next();

            UserLoginEntity _userLogin = userLoginMap.get(
                    userLogin.getUserId() + Constant.SPLIT + userLogin.getChannel()
            );
            if (Objects.isNull(_userLogin)) {
                log.error("用户登录记录不存在。userId={} channel={}", userLogin.getUserId(), userLogin.getChannel());
                userLoginIterator.remove();
                continue;
            }
            UserLoginEntity updateUserLogin = new UserLoginEntity();
            updateUserLogin.setId(_userLogin.getId())
                    .setType(CommonEnum.MINUS_ONE.getValue())
                    .setLoginIp(StringUtils.EMPTY)
                    .setLoginAddress(StringUtils.EMPTY)
                    .setLoginTime(CommonEnum.ZERO.getLongValue())
                    .setExpireTime(CommonEnum.ZERO.getLongValue())
                    .setStatus(CommonEnum.TWO.getValue())
                    .setUpdateTime(date)
                    .setUpdateUser(optUsername)
                    .setUpdateUserId(optUserId);
            updateUserLoginList.add(updateUserLogin);
        }
        if (!updateUserLoginList.isEmpty()) {
            userLoginService.batchUpdate(updateUserLoginList);
        }

        /*
            删除登录用户缓存
         */
        List<String> securityUserKeyList = CopyUtils.mapList(userLoginList, userLogin -> {
            String name = RequestChannelEnum.getName(userLogin.getChannel());
            return CacheKeyUtils.getSecurityUserKey(userLogin.getUserId());
        });
        if (!securityUserKeyList.isEmpty()) {
            redisHandler.delete(securityUserKeyList);
        }
    }

    public void updateMySelf(UserVo userVo) {
        // 获取当前修改自己个人信息的用户对象
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        // 从上下文参数中获取请求IP地址
        String requestIp = ContextUtils.get(Constant.REQUEST_IP);

        if (!userPo.getUserId().equals(userVo.getUserId())) {
            throw new CzzException(ResultEnum.ILLEGAL_FAIL);
        }

        // 手机号加密
        String phone = Optional.ofNullable(userVo.getPhone())
                .filter(StringUtils::isNotBlank)
                .map(aesService::encryptToHex)
                .orElse(StringUtils.EMPTY);
        // 邮箱号加密
        String email = Optional.ofNullable(userVo.getEmail())
                .filter(StringUtils::isNotBlank)
                .map(aesService::encryptToHex)
                .orElse(StringUtils.EMPTY);
        String loginName= Optional.ofNullable(userVo.getLoginName()).orElse(StringUtils.EMPTY);

        /*
            检查用户是否允许添加
         */
        userService.checkLoginInfo(userVo.getUserId(), phone, email, userVo.getLoginName());

        // 异步执行
        CompletableFuture<CzzException> phoneFuture = asyncService.supplyAsync(() -> {
            CzzException czzException = null;
            try {
                if (StringUtils.isNotBlank(userVo.getPhone())) {
                    // 短信验证码校验
                    validateCodeService.checkValidateCode(userVo.getPhone(), requestIp,
                            ValidateCodeTypeEnum.UPDATE_PHONE, userVo.getPhoneCode());
                }
            } catch (CzzException e) {
                czzException = e;
            } catch (Exception e) {
                czzException = new CzzException(ResultEnum.SERVICE_FAIL);
            }
            return czzException;
        });
        // 异步执行
        CompletableFuture<CzzException> emailFuture = asyncService.supplyAsync(() -> {
            CzzException czzException = null;
            try {
                if (StringUtils.isNotBlank(userVo.getPhone())) {
                    // 邮箱验证码校验
                    validateCodeService.checkValidateCode(userVo.getEmail(), requestIp,
                            ValidateCodeTypeEnum.UPDATE_EMAIL, userVo.getPhoneCode());
                }
            } catch (CzzException e) {
                czzException = e;
            } catch (Exception e) {
                czzException = new CzzException(ResultEnum.SERVICE_FAIL);
            }
            return czzException;
        });

        try {
            List<CzzException> list = new ArrayList<>();
            list.add(phoneFuture.get());
            list.add(emailFuture.get());
            for (CzzException czzException : list) {
                if (czzException != null) {
                    throw czzException;
                }
            }
        } catch (InterruptedException | ExecutionException e) {
            log.error("异步校验数据操作异常。message={}", e.getMessage(), e);
            throw new CzzException();
        }

        /*
            获取用户
         */
        UserEntity user = userHelper.get(userVo.getUserId());

        /*
            修改用户
         */
        UserEntity updateUser = new UserEntity();
        updateUser.setUserId(userVo.getUserId())
                .setUsername(userVo.getUsername())
                .setPhone(phone)
                .setEmail(email)
                .setLoginName(loginName)
                .setUpdateTime(date)
                .setUpdateUser(userPo.getUsername())
                .setUpdateUserId(userPo.getUserId());
        userService.saveOrEdit(updateUser);

        // 删除所有用户相关的临时缓存数据
        this.deleteUserCache(Collections.singletonList(userVo.getUserId()));

        asyncService.execute(() -> {
            List<UserContactFlowEntity> userContactFlowList = new ArrayList<>();
            if (StringUtils.isNotBlank(phone) && !user.getPhone().equals(phone)) {
                UserContactFlowEntity userContactFlow = new UserContactFlowEntity();
                userContactFlow.setUserId(userVo.getUserId())
                        .setType(UserContactFlowEnum.PHONE.getValue())
                        .setMode(UserContactFlowEnum.BIND.getValue())
                        .setContact(phone)
                        .setDeleteFlag(CommonEnum.ZERO.getValue())
                        .setDeleteTime(date)
                        .setCreateTime(date)
                        .setCreateUser(userPo.getUserId());
                userContactFlowList.add(userContactFlow);
            }
            if (StringUtils.isNotBlank(email) && !user.getEmail().equals(email)) {
                UserContactFlowEntity userContactFlow = new UserContactFlowEntity();
                userContactFlow.setUserId(userVo.getUserId())
                        .setType(UserContactFlowEnum.EMAIL.getValue())
                        .setMode(UserContactFlowEnum.BIND.getValue())
                        .setContact(email)
                        .setDeleteFlag(CommonEnum.ZERO.getValue())
                        .setDeleteTime(date)
                        .setCreateTime(date)
                        .setCreateUser(userPo.getUserId());
                userContactFlowList.add(userContactFlow);
            }
            if (!userContactFlowList.isEmpty()) {
                userContactFlowService.batchSave(userContactFlowList);
            }
        });
    }

    public void updateUser(UserVo userVo) {
        // 获取操作用户
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        if (userPo.getUserId().equals(userVo.getUserId())) {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "您不能修改自己，操作失败");
        }

        // 手机号加密
        String phone = Optional.ofNullable(userVo.getPhone())
                .filter(StringUtils::isNotBlank)
                .map(aesService::encryptToHex)
                .orElse(StringUtils.EMPTY);
        // 邮箱号加密
        String email = Optional.ofNullable(userVo.getEmail())
                .filter(StringUtils::isNotBlank)
                .map(aesService::encryptToHex)
                .orElse(StringUtils.EMPTY);
        String loginName= Optional.ofNullable(userVo.getLoginName()).orElse(StringUtils.EMPTY);

        /*
            检查用户是否允许添加
         */
        userService.checkLoginInfo(userVo.getUserId(), phone, email, userVo.getLoginName());

        /*
            获取用户
         */
        UserEntity user = userHelper.get(userVo.getUserId());

        /*
            修改用户
         */
        UserEntity updateUser = new UserEntity();
        updateUser.setUserId(userVo.getUserId())
                .setUsername(userVo.getUsername())
                .setPhone(phone)
                .setEmail(email)
                .setLoginName(loginName)
                .setUpdateTime(date)
                .setUpdateUser(userPo.getUsername())
                .setUpdateUserId(userPo.getUserId());
        userService.saveOrEdit(updateUser);

        // 删除所有用户相关的临时缓存数据
        this.deleteUserCache(Collections.singletonList(userVo.getUserId()));

        asyncService.execute(() -> {
            List<UserContactFlowEntity> userContactFlowList = new ArrayList<>();
            if (StringUtils.isNotBlank(phone) && !user.getPhone().equals(phone)) {
                UserContactFlowEntity userContactFlow = new UserContactFlowEntity();
                userContactFlow.setUserId(userVo.getUserId())
                        .setType(UserContactFlowEnum.PHONE.getValue())
                        .setMode(UserContactFlowEnum.BIND.getValue())
                        .setContact(phone)
                        .setDeleteFlag(CommonEnum.ZERO.getValue())
                        .setDeleteTime(date)
                        .setCreateTime(date)
                        .setCreateUser(userPo.getUserId());
                userContactFlowList.add(userContactFlow);
            }
            if (StringUtils.isNotBlank(email) && !user.getEmail().equals(email)) {
                UserContactFlowEntity userContactFlow = new UserContactFlowEntity();
                userContactFlow.setUserId(userVo.getUserId())
                        .setType(UserContactFlowEnum.EMAIL.getValue())
                        .setMode(UserContactFlowEnum.BIND.getValue())
                        .setContact(email)
                        .setDeleteFlag(CommonEnum.ZERO.getValue())
                        .setDeleteTime(date)
                        .setCreateTime(date)
                        .setCreateUser(userPo.getUserId());
                userContactFlowList.add(userContactFlow);
            }
            if (!userContactFlowList.isEmpty()) {
                userContactFlowService.batchSave(userContactFlowList);
            }
        });
    }

    public void userPwdUpdate(UpdatePasswordVo updatePasswordVo) {
        // 获取当前正在修改自己登录密码的用户id
        UserPo userPo = SecurityUtils.getUser();

        // 查询数据库用户信息表，获取用户密码
        UserEntity user = userHelper.get(userPo.getUserId());

        // 旧密码解密（凯撒移位算法解密）
        String oPassWord = CaesarUtils.decodePwd(updatePasswordVo.getOldPassword());
        // 旧密码加密
        oPassWord = ShaUtils.encodeSha256(oPassWord, user.getSalt());
        if (!user.getPassword().equals(oPassWord)) {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "输入原密码不对，请确认后重新输入!");
        }
        // 新密码解密（凯撒移位算法解密）
        String nPassWord = CaesarUtils.decodePwd(updatePasswordVo.getNewPassword());
        // 新密码加密
        nPassWord = ShaUtils.encodeSha256(nPassWord, user.getSalt());

        // 获取用户最近使用过程前三个登录密码
        List<String> oldPasswordList = historyPasswordService.getFirst3OldPasswordByUserId(userPo.getUserId());
        // 判断新密码是否与最近三次密码相同
        for (String oldPassword : oldPasswordList) {
            if (nPassWord.equals(oldPassword)) {
                throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "新密码不能与最近三次使用的密码相同,请重新输入！");
            }
        }
        // 密码加密
        String password = nPassWord;

        /*
            修改用户密码
         */
        userService.updatePassword(user.getUserId(), password);

        asyncService.execute(() -> {
            // 记录用户密码使用记录（异步保存）
            historyPasswordService.saveUserPassword(userPo.getUserId(), password);
        });
    }

    public void userPasswordReset(UpdatePasswordVo updatePasswordVo) {

        /*
            获取用户
         */
        UserEntity user = userHelper.get(updatePasswordVo.getUserId());

        // 根据用户id，获取用户最近使用的前三个旧密码
        List<String> oldPasswordList = historyPasswordService.getFirst3OldPasswordByUserId(updatePasswordVo.getUserId());

        // 新密码解密（凯撒移位算法解密）
        String password = CaesarUtils.decodePwd(updatePasswordVo.getNewPassword());
        // 新密码加密
        password = ShaUtils.encodeSha256(password, user.getSalt());
        for (String oldPassword : oldPasswordList) {
            if (password.equals(oldPassword)) {
                throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(),
                        "重置密码不能与用户近三次使用的密码相同，请确认，如有问题，请联系客服处理。");
            }
        }
        String newPassword = password;

        /*
            修改用户密码
         */
        userService.updatePassword(updatePasswordVo.getUserId(), newPassword);

        asyncService.execute(() -> {
            // 记录用户密码使用记录（异步保存）
            historyPasswordService.saveUserPassword(updatePasswordVo.getUserId(), newPassword);
        });
    }

    public void oneUserMove(DeptUserFlowVo deptUserFlowVo) {
        // 获取正在执行用户切换部门操作的用户主键
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        Long userId = deptUserFlowVo.getUserIds().get(0);

        /*
            获取用户关联部门
         */
        List<DeptUserEntity> deptUserList = deptUserService.findList(null, Collections.singletonList(userId));
        // 部门主键集合，查询数据用
        Set<Long> deptIdSet = new HashSet<>();
        // 用户主业务部门主键列表
        List<Long> masterDeptIdList = new ArrayList<>();
        // 用户已关联部门主键
        Long currentDeptId = null;
        for (DeptUserEntity deptUser : deptUserList) {
            deptIdSet.add(deptUser.getDeptId());

            // 判断遍历到的部门是否旧部门
            boolean bool = deptUser.getDeptId().equals(deptUserFlowVo.getPreDeptId());

            // 主业务部门 且 不是旧部门
            if (CommonEnum.ZERO.getValue().equals(deptUser.getMasterStatus()) && !bool) {
                masterDeptIdList.add(deptUser.getDeptId());
            }

            // 旧部门
            if (bool) {
                currentDeptId = deptUser.getId();
            }
            if (deptUser.getDeptId().equals(deptUserFlowVo.getNextDeptId())) {
                log.info("【单个用户切换部门】用户已关联部门");
                throw new CzzException(ResultEnum.DATA_DUPLICATION.getCode(), "用户已关联新部门，无需切换");
            }
        }
        if (Objects.isNull(currentDeptId)) {
            log.info("【单个用户切换部门】用户未关联旧部门");
            throw new CzzException(ResultEnum.ILLEGAL_FAIL);
        }
        deptIdSet.add(deptUserFlowVo.getNextDeptId());

        /*
            获取部门
         */
        List<DeptEntity> deptList = deptService.getList(new ArrayList<>(deptIdSet));
        // 部门映射
        Map<Long, DeptEntity> deptMap = new HashMap<>();
        for (DeptEntity dept : deptList) {
            // 添加映射
            deptMap.put(dept.getId(), dept);

            // 获取所有父级部门主键
            String deptPath = dept.getParentPath();
            List<Long> parentIdList = Stream.of(deptPath.split(Constant.SPLIT))
                    .map(Long::valueOf)
                    .filter(_id -> !CommonEnum.ZERO.getLongValue().equals(_id))
                    .collect(Collectors.toList());
            deptIdSet.addAll(parentIdList);
        }
        // 获取旧部门对象，采取从映射中删除的方式，方便下面操作
        DeptEntity preDept = deptMap.remove(deptUserFlowVo.getPreDeptId());
        if (Objects.isNull(preDept)) {
            log.info("【单个用户切换部门】用户关联旧部门不存在");
            throw new CzzException(ResultEnum.ILLEGAL_FAIL);
        }
        // 获取新部门对象，采取从映射中删除的方式，方便下面操作
        DeptEntity nextDept = deptMap.remove(deptUserFlowVo.getNextDeptId());
        if (Objects.isNull(nextDept)) {
            log.info("【单个用户切换部门】用户要关联的部门不存在");
            throw new CzzException(ResultEnum.REQUEST_FAIL);
        }

        /*
            获取部门关联角色
         */
        List<DeptRoleEntity> deptRoleList = deptRoleService.findList(new ArrayList<>(deptIdSet), null);
        // 按部门分组
        Map<Long, List<DeptRoleEntity>> deptRoleMap = deptRoleList.stream()
                .collect(Collectors.groupingBy(DeptRoleEntity::getDeptId));

        // 过滤禁用数据
        Predicate<DeptRoleEntity> statusFilter = deptRole ->
                CommonEnum.ZERO.getValue().equals(deptRole.getStatus());
        // 过滤领导专属数据
        Predicate<DeptRoleEntity> leaderFilter = deptRole ->
                CommonEnum.ONE.getValue().equals(deptRole.getUseLeader());

        // 获取新部门关联的角色列表
        deptRoleList = deptRoleMap.getOrDefault(deptUserFlowVo.getNextDeptId(), Collections.emptyList());
        // 映射待新增角色主键
        TreeSet<Long> newRoleIdSet = deptRoleList.stream()
                // 只取可用数据
                .filter(statusFilter)
                // 只取非领导数据
                .filter(leaderFilter)
                .map(DeptRoleEntity::getRoleId)
                .collect(Collectors.toCollection(TreeSet::new));

        // 追加待新增角色主键
        Stream.of(nextDept.getParentPath().split(Constant.SPLIT))
                .map(Long::valueOf)
                .filter(deptId -> !CommonEnum.ZERO.getLongValue().equals(deptId))
                .flatMap(deptId -> {
                    // 从映射中获取新部门的父级部门关联的角色列表映射
                    List<DeptRoleEntity> list = deptRoleMap.get(deptId);
                    if (CollectionUtils.isEmpty(list)) {
                        return Stream.empty();
                    }
                    return list.stream();
                })
                // 只取可用数据
                .filter(statusFilter)
                // 只取非领导数据
                .filter(leaderFilter)
                // 只取权限范围是所有子部门的数据
                .filter(deptRole -> CommonEnum.ONE.getValue().equals(deptRole.getUseRange()))
                .map(DeptRoleEntity::getRoleId)
                .forEach(newRoleIdSet::add);
        log.info("【单个用户切换部门】newRoleIdSet={}", newRoleIdSet);

        // 用户关联其他部门及其所有父级部门关联的角色集合，这部门数据不需要改变
        Set<Long> otherRoleIdSet = new HashSet<>();

        // 遍历用户剩余关联部门
        for (DeptEntity dept : deptMap.values()) {
            deptRoleList = deptRoleMap.get(dept.getId());
            if (!CollectionUtils.isEmpty(deptRoleList)) {
                // 添加
                otherRoleIdSet.addAll(CopyUtils.mapSet(deptRoleList, DeptRoleEntity::getRoleId));
            }
            // 追加
            Stream.of(dept.getParentPath().split(Constant.SPLIT))
                    .map(Long::valueOf)
                    .filter(id -> !CommonEnum.ZERO.getLongValue().equals(id))
                    .flatMap(deptId -> {
                        // 从映射中获取已关联部门的父级部门关联的角色列表
                        List<DeptRoleEntity> list = deptRoleMap.get(deptId);
                        if (CollectionUtils.isEmpty(list)) {
                            return Stream.empty();
                        }
                        return list.stream();
                    })
                    // 只取可用数据
                    .filter(statusFilter)
                    // 只取非领导数据
                    .filter(leaderFilter)
                    // 只取权限范围是所有子部门的数据
                    .filter(deptRole -> CommonEnum.ONE.getValue().equals(deptRole.getUseRange()))
                    .map(DeptRoleEntity::getRoleId)
                    .forEach(otherRoleIdSet::add);
        }
        log.info("【单个用户切换部门】otherRoleIdSet={}", otherRoleIdSet);

        /*
            获取用户关联角色
         */
        List<UserRoleEntity> userRoleList = userRoleService.findUserRoleList(Collections.singletonList(userId),
                null, Collections.singletonList(RelationModeEnum.DEPT_ROLE.getValue()));

        List<UserRoleEntity> addUserRoleList = new ArrayList<>();
        List<UserRoleEntity> updateUserRoleList = new ArrayList<>();

        for (UserRoleEntity userRole : userRoleList) {
            if (otherRoleIdSet.contains(userRole.getRoleId())) {
                /*
                    用户其他已关联部门，部门关联的角色包含遍历到的角色
                    其他已关联部门：
                        1、除preDeptId及其所有父级部门外的部门
                        2、除nextDeptId及其所有父级部门外的部门
                        3、剩余部门及其所有父级部，3涉及到的部门可能包含1和2里的部门，因为用户关联的部门可能是同一个父级部门下的子部门
                 */
                log.info("【单个用户切换部门】用户其他已关联部门，部门关联的角色包含遍历到的角色。roleId={}", userRole.getRoleId());
                continue;
            }
            if (newRoleIdSet.remove(userRole.getRoleId())) {
                log.info("【单个用户切换部门】用户新关联部门，部门关联的角色包含遍历到的角色。roleId={}", userRole.getRoleId());
                continue;
            }

            UserRoleEntity updateUserRole = new UserRoleEntity();
            updateUserRole.setId(userRole.getId());
            if (!newRoleIdSet.isEmpty()) {
                /*
                    关联关系修改
                 */
                Long roleId = newRoleIdSet.pollFirst();

                updateUserRole.setRoleId(roleId)
                        .setUpdateTime(date)
                        .setUpdateUser(userPo.getUsername())
                        .setUpdateUserId(userPo.getUserId());
                updateUserRoleList.add(updateUserRole);
            } else {
                // 删除关联关系
                updateUserRole.setDeleteStatus(CommonEnum.ONE.getValue())
                        .setUpdateTime(date)
                        .setUpdateUser(userPo.getUsername())
                        .setUpdateUserId(userPo.getUserId());
                updateUserRoleList.add(updateUserRole);
            }
        }
        // 迭代器剩余角色主键全部添加
        for (Long roleId : newRoleIdSet) {
            if (otherRoleIdSet.contains(roleId)) {
                // 逻辑同上面for
                continue;
            }
            addUserRoleList.add(this.buildUserRole(userId, roleId, date, userPo));
        }

        log.info("【单个用户切换部门】masterDeptIdList={}", masterDeptIdList);
        boolean bool = masterDeptIdList.stream()
                .map(deptMap::get)
                .filter(Objects::nonNull)
                .noneMatch(dept -> nextDept.getBusinessType().equals(dept.getBusinessType()));

        Integer masterStatus = bool ? CommonEnum.ZERO.getValue() : CommonEnum.ONE.getValue();

        // 为用户设置新部门
        DeptUserEntity updateDeptUser = new DeptUserEntity();
        updateDeptUser.setId(currentDeptId)
                .setDeptId(deptUserFlowVo.getNextDeptId())
                .setMasterStatus(masterStatus)
                .setLeaderStatus(CommonEnum.ONE.getValue())
                .setUpdateTime(date)
                .setUpdateUser(userPo.getUsername())
                .setUpdateUserId(userPo.getUserId());

        // 用户切换部门记录
        DeptUserFlowEntity userDeptFlow = this.getUserDeptFlow(deptUserFlowVo, userId, userPo, date);

        transactionService.execute(() -> {
            /*
                更新用户关联部门
             */
            deptUserService.saveOrEdit(updateDeptUser);

            /*
                添加用户新关联角色
             */
            if (!addUserRoleList.isEmpty()) {
                userRoleService.batchSave(addUserRoleList);
            }

            /*
                修改用户关联角色
             */
            if (!updateUserRoleList.isEmpty()) {
                userRoleService.batchUpdate(updateUserRoleList);
            }

            /*
                保存用户切换部门流水
             */
            deptUserFlowService.saveOrEdit(userDeptFlow);
        });

        if (!addUserRoleList.isEmpty() || !updateUserRoleList.isEmpty()) {
            // 发送MQ消息
            rabbitHelper.send(MqEnum.DEPT_USER, Collections.singletonList(userId));
        }

        // 删除用户临时缓存
        this.deleteUserCache(Collections.singletonList(userId));
    }

    public void batchUserMove(DeptUserFlowVo deptUserFlowVo) {
        // 获取正在执行用户切换部门操作的用户主键
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        List<Long> userIdList = deptUserFlowVo.getUserIds();

        /*
            获取用户名称映射
         */
        Map<Long, String> usernameMap = userService.getNameMap(userIdList, Function.identity());

        /*
            获取用户关联部门
         */
        List<DeptUserEntity> deptUserList = deptUserService.findList(null, userIdList);

        // 部门主键集合，查询数据用
        Set<Long> deptIdSet = new HashSet<>();
        // 用户主业务部门主键列表
        Map<Long, List<Long>> masterDeptIdMap = new HashMap<>();
        // 用户已关联部门
        Map<Long, DeptUserEntity> updateDeptUserMap = new HashMap<>();

        for (DeptUserEntity deptUser : deptUserList) {
            deptIdSet.add(deptUser.getDeptId());

            // 判断遍历到的部门是否旧部门
            boolean bool = deptUser.getDeptId().equals(deptUserFlowVo.getPreDeptId());

            // 主业务部门 且 不是旧部门
            if (CommonEnum.ZERO.getValue().equals(deptUser.getMasterStatus()) && !bool) {
                masterDeptIdMap.computeIfAbsent(deptUser.getUserId(), key -> new ArrayList<>())
                        .add(deptUser.getDeptId());
            }

            // 旧部门
            if (bool) {
                DeptUserEntity updateDeptUser = new DeptUserEntity();
                updateDeptUser.setId(deptUser.getId());

                updateDeptUserMap.put(deptUser.getUserId(), updateDeptUser);
            }
            if (deptUser.getDeptId().equals(deptUserFlowVo.getNextDeptId())) {
                log.info("【批量用户切换部门】用户已关联新部门。userId={} username={}", deptUser.getUserId(),
                        usernameMap.get(deptUser.getUserId()));
                String message = usernameMap.get(deptUser.getUserId()) + "用户已关联新部门，操作失败";
                throw new CzzException(ResultEnum.DATA_DUPLICATION.getCode(), message);
            }
        }
        if (updateDeptUserMap.size() != userIdList.size()) {
            log.info("【批量用户切换部门】存在用户未关联旧部门");
            throw new CzzException(ResultEnum.ILLEGAL_FAIL);
        }
        deptIdSet.add(deptUserFlowVo.getNextDeptId());

        log.info("【批量用户切换部门】updateDeptUserMap.keySet={}", updateDeptUserMap.keySet());

        /*
            获取部门
         */
        List<DeptEntity> deptList = deptService.getList(new ArrayList<>(deptIdSet));
        // 部门映射
        Map<Long, DeptEntity> deptMap = new HashMap<>();
        for (DeptEntity dept : deptList) {
            // 添加映射
            deptMap.put(dept.getId(), dept);

            // 获取所有父级部门主键
            String deptPath = dept.getParentPath();
            List<Long> parentIdList = Stream.of(deptPath.split(Constant.SPLIT))
                    .map(Long::valueOf)
                    .filter(_id -> !CommonEnum.ZERO.getLongValue().equals(_id))
                    .collect(Collectors.toList());
            deptIdSet.addAll(parentIdList);
        }
        // 获取旧部门对象，采取从映射中删除的方式，方便下面操作
        DeptEntity preDept = deptMap.remove(deptUserFlowVo.getPreDeptId());
        if (Objects.isNull(preDept)) {
            log.info("【批量用户切换部门】用户关联旧部门不存在");
            throw new CzzException(ResultEnum.ILLEGAL_FAIL);
        }
        // 获取新部门对象，采取从映射中删除的方式，方便下面操作
        DeptEntity nextDept = deptMap.remove(deptUserFlowVo.getNextDeptId());
        if (Objects.isNull(nextDept)) {
            log.info("【批量用户切换部门】用户要关联的部门不存在");
            throw new CzzException(ResultEnum.REQUEST_FAIL);
        }

        /*
            获取部门关联角色
         */
        List<DeptRoleEntity> deptRoleList = deptRoleService.findList(new ArrayList<>(deptIdSet), null);
        // 按部门分组
        Map<Long, List<DeptRoleEntity>> deptRoleMap = deptRoleList.stream()
                .collect(Collectors.groupingBy(DeptRoleEntity::getDeptId));

        // 过滤禁用数据
        Predicate<DeptRoleEntity> statusFilter = deptRole ->
                CommonEnum.ZERO.getValue().equals(deptRole.getStatus());
        // 过滤领导专属数据
        Predicate<DeptRoleEntity> leaderFilter = deptRole ->
                CommonEnum.ONE.getValue().equals(deptRole.getUseLeader());

        // 获取新部门关联的角色列表
        deptRoleList = deptRoleMap.getOrDefault(deptUserFlowVo.getNextDeptId(), Collections.emptyList());
        // 映射待新增角色主键
        Set<Long> newRoleIdSet = deptRoleList.stream()
                // 只取可用数据
                .filter(statusFilter)
                // 只取非领导数据
                .filter(leaderFilter)
                .map(DeptRoleEntity::getRoleId)
                .collect(Collectors.toSet());

        // 追加待新增角色主键
        Stream.of(nextDept.getParentPath().split(Constant.SPLIT))
                .map(Long::valueOf)
                .filter(deptId -> !CommonEnum.ZERO.getLongValue().equals(deptId))
                .flatMap(deptId -> {
                    // 从映射中获取新部门的父级部门关联的角色列表映射
                    List<DeptRoleEntity> list = deptRoleMap.get(deptId);
                    if (CollectionUtils.isEmpty(list)) {
                        return Stream.empty();
                    }
                    return list.stream();
                })
                // 只取可用数据
                .filter(statusFilter)
                // 只取非领导数据
                .filter(leaderFilter)
                // 只取权限范围是所有子部门的数据
                .filter(deptRole -> CommonEnum.ONE.getValue().equals(deptRole.getUseRange()))
                .map(DeptRoleEntity::getRoleId)
                .forEach(newRoleIdSet::add);
        log.info("【批量用户切换部门】newRoleIdSet={}", newRoleIdSet);

        // 用户关联其他部门及其所有父级部门关联的角色集合，这部门数据不需要改变
        Set<Long> otherRoleIdSet = new HashSet<>();

        // 遍历用户剩余关联部门
        for (DeptEntity dept : deptMap.values()) {
            deptRoleList = deptRoleMap.get(dept.getId());
            if (!CollectionUtils.isEmpty(deptRoleList)) {
                // 添加
                otherRoleIdSet.addAll(CopyUtils.mapSet(deptRoleList, DeptRoleEntity::getRoleId));
            }
            // 追加
            Stream.of(dept.getParentPath().split(Constant.SPLIT))
                    .map(Long::valueOf)
                    .filter(id -> !CommonEnum.ZERO.getLongValue().equals(id))
                    .flatMap(deptId -> {
                        // 从映射中获取已关联部门的父级部门关联的角色列表
                        List<DeptRoleEntity> list = deptRoleMap.get(deptId);
                        if (CollectionUtils.isEmpty(list)) {
                            return Stream.empty();
                        }
                        return list.stream();
                    })
                    // 只取可用数据
                    .filter(statusFilter)
                    // 只取非领导数据
                    .filter(leaderFilter)
                    // 只取权限范围是所有子部门的数据
                    .filter(deptRole -> CommonEnum.ONE.getValue().equals(deptRole.getUseRange()))
                    .map(DeptRoleEntity::getRoleId)
                    .forEach(otherRoleIdSet::add);
        }
        log.info("【批量用户切换部门】otherRoleIdSet={}", otherRoleIdSet);

        /*
            获取用户关联角色
         */
        List<UserRoleEntity> userRoleList = userRoleService.findUserRoleList(userIdList, null,
                Collections.singletonList(RelationModeEnum.DEPT_ROLE.getValue()));
        // 分组
        Map<Long, List<UserRoleEntity>> userRoleMap = userRoleList.stream()
                .collect(Collectors.groupingBy(UserRoleEntity::getUserId));
        // 填充数据，确保每个用户都可以计算到
        for (Long userId : userIdList) {
            userRoleList = userRoleMap.get(userId);
            if (Objects.isNull(userRoleList)) {
                userRoleMap.put(userId, Collections.emptyList());
            }
        }

        List<UserRoleEntity> addUserRoleList = new ArrayList<>();
        List<UserRoleEntity> updateUserRoleList = new ArrayList<>();
        List<DeptUserEntity> updateDeptUserList = new ArrayList<>();

        for (Map.Entry<Long, List<UserRoleEntity>> entry : userRoleMap.entrySet()) {
            Long userId = entry.getKey();
            userRoleList = entry.getValue();

            TreeSet<Long> addSet = new TreeSet<>(newRoleIdSet);

            for (UserRoleEntity userRole : userRoleList) {
                if (otherRoleIdSet.contains(userRole.getRoleId())) {
                    /*
                        用户其他已关联部门，部门关联的角色包含遍历到的角色
                        其他已关联部门：
                            1、除preDeptId及其所有父级部门外的部门
                            2、除nextDeptId及其所有父级部门外的部门
                            3、剩余部门及其所有父级部，3涉及到的部门可能包含1和2里的部门，因为用户关联的部门可能是同一个父级部门下的子部门
                     */
                    log.info("【批量用户切换部门】用户其他已关联部门，部门关联的角色包含遍历到的角色。roleId={}", userRole.getRoleId());
                    continue;
                }
                if (addSet.remove(userRole.getRoleId())) {
                    log.info("【批量用户切换部门】用户新关联部门，部门关联的角色包含遍历到的角色。roleId={}", userRole.getRoleId());
                    continue;
                }

                UserRoleEntity updateUserRole = new UserRoleEntity();
                updateUserRole.setId(userRole.getId());
                if (!addSet.isEmpty()) {
                    /*
                        关联关系修改
                     */
                    Long roleId = addSet.pollFirst();

                    updateUserRole.setRoleId(roleId)
                            .setUpdateTime(date)
                            .setUpdateUser(userPo.getUsername())
                            .setUpdateUserId(userPo.getUserId());
                    updateUserRoleList.add(updateUserRole);
                } else {
                    // 删除关联关系
                    updateUserRole.setDeleteStatus(CommonEnum.ONE.getValue())
                            .setUpdateTime(date)
                            .setUpdateUser(userPo.getUsername())
                            .setUpdateUserId(userPo.getUserId());
                    updateUserRoleList.add(updateUserRole);
                }
            }
            // 迭代器剩余角色主键全部添加
            for (Long roleId : addSet) {
                if (otherRoleIdSet.contains(roleId)) {
                    // 逻辑同上面for
                    continue;
                }
                addUserRoleList.add(this.buildUserRole(userId, roleId, date, userPo));
            }

            List<Long> masterDeptIdList = masterDeptIdMap.getOrDefault(userId, Collections.emptyList());
            log.info("【批量用户切换部门】userId={} masterDeptIdList={}", userId, masterDeptIdList);
            boolean bool = masterDeptIdList.stream()
                    .map(deptMap::get)
                    .filter(Objects::nonNull)
                    .noneMatch(dept -> nextDept.getBusinessType().equals(dept.getBusinessType()));

            Integer masterStatus = bool ? CommonEnum.ZERO.getValue() : CommonEnum.ONE.getValue();

            // 为用户设置新部门
            DeptUserEntity updateDeptUser = updateDeptUserMap.get(userId);
            if (Objects.isNull(updateDeptUser)) {
                log.info("【批量用户切换部门】获取用户关联部门对象失败。userId={}", userId);
                throw new CzzException();
            }
            updateDeptUser.setDeptId(deptUserFlowVo.getNextDeptId())
                    .setMasterStatus(masterStatus)
                    .setLeaderStatus(CommonEnum.ONE.getValue())
                    .setUpdateTime(date)
                    .setUpdateUser(userPo.getUsername())
                    .setUpdateUserId(userPo.getUserId());
            updateDeptUserList.add(updateDeptUser);

        }

        // 用户切换部门流水映射
        List<DeptUserFlowEntity> userDeptFlowList = CopyUtils.mapList(userIdList, (userId) ->
                this.getUserDeptFlow(deptUserFlowVo, userId, userPo, date)
        );

        transactionService.execute(() -> {
            /*
                 修改部门关联用户
             */
            deptUserService.batchUpdate(updateDeptUserList);

            /*
                添加用户新关联角色
             */
            if (!addUserRoleList.isEmpty()) {
                userRoleService.batchSave(addUserRoleList);
            }

            /*
                修改用户关联角色
             */
            if (!updateUserRoleList.isEmpty()) {
                userRoleService.batchUpdate(updateUserRoleList);
            }

            /*
                批量保存用户切换部门流水
             */
            deptUserFlowService.batchSave(userDeptFlowList);
        });

        if (!addUserRoleList.isEmpty() || !updateUserRoleList.isEmpty()) {
            // 发送mq消息
            rabbitHelper.send(MqEnum.DEPT_USER, userIdList);
        }

        /*
            删除用户临时缓存
         */
        this.deleteUserCache(userIdList);
    }

    public void allUserMove(DeptUserFlowVo deptUserFlowVo) {
        // 获取正在执行用户切换部门操作的用户主键
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        List<Long> deptIdList = Collections.singletonList(deptUserFlowVo.getPreDeptId());

        /*
            获取部门关联用户
         */
        List<DeptUserEntity> deptUserList = deptUserService.findList(deptIdList, null);
        if (deptUserList.isEmpty()) {
            log.info("部门关联用户为空");
            throw new CzzException(ResultEnum.NOT_FOUND.getCode(), "选择部门没有用户，操作失败");
        }

        List<Long> userIdList = CopyUtils.mapList(deptUserList, DeptUserEntity::getUserId);

        /*
            获取用户名称映射
         */
        Map<Long, String> usernameMap = userService.getNameMap(userIdList, Function.identity());

        // 部门主键集合，查询数据用
        Set<Long> deptIdSet = new HashSet<>();
        // 用户主业务部门主键列表
        Map<Long, List<Long>> masterDeptIdMap = new HashMap<>();
        // 用户已关联部门
        Map<Long, DeptUserEntity> updateDeptUserMap = new HashMap<>();

        for (DeptUserEntity deptUser : deptUserList) {
            deptIdSet.add(deptUser.getDeptId());

            // 判断遍历到的部门是否旧部门
            boolean bool = deptUser.getDeptId().equals(deptUserFlowVo.getPreDeptId());

            // 主业务部门 且 不是旧部门
            if (CommonEnum.ZERO.getValue().equals(deptUser.getMasterStatus()) && !bool) {
                masterDeptIdMap.computeIfAbsent(deptUser.getUserId(), key -> new ArrayList<>())
                        .add(deptUser.getDeptId());
            }

            // 旧部门
            if (bool) {
                DeptUserEntity updateDeptUser = new DeptUserEntity();
                updateDeptUser.setId(deptUser.getId());

                updateDeptUserMap.put(deptUser.getUserId(), updateDeptUser);
            }
            if (deptUser.getDeptId().equals(deptUserFlowVo.getNextDeptId())) {
                log.info("【部门用户集体切换部门】用户已关联新部门。userId={} username={}", deptUser.getUserId(),
                        usernameMap.get(deptUser.getUserId()));
                String message = usernameMap.get(deptUser.getUserId()) + "用户已关联新部门，操作失败";
                throw new CzzException(ResultEnum.DATA_DUPLICATION.getCode(), message);
            }
        }
        if (updateDeptUserMap.size() != userIdList.size()) {
            log.info("【部门用户集体切换部门】存在用户未关联旧部门");
            throw new CzzException(ResultEnum.ILLEGAL_FAIL);
        }
        deptIdSet.add(deptUserFlowVo.getNextDeptId());

        log.info("【部门用户集体切换部门】updateDeptUserMap.keySet={}", updateDeptUserMap.keySet());

        /*
            获取部门
         */
        List<DeptEntity> deptList = deptService.getList(new ArrayList<>(deptIdSet));
        // 部门映射
        Map<Long, DeptEntity> deptMap = new HashMap<>();
        for (DeptEntity dept : deptList) {
            // 添加映射
            deptMap.put(dept.getId(), dept);

            // 获取所有父级部门主键
            String deptPath = dept.getParentPath();
            List<Long> parentIdList = Stream.of(deptPath.split(Constant.SPLIT))
                    .map(Long::valueOf)
                    .filter(_id -> !CommonEnum.ZERO.getLongValue().equals(_id))
                    .collect(Collectors.toList());
            deptIdSet.addAll(parentIdList);
        }
        // 获取旧部门对象，采取从映射中删除的方式，方便下面操作
        DeptEntity preDept = deptMap.remove(deptUserFlowVo.getPreDeptId());
        if (Objects.isNull(preDept)) {
            log.info("【部门用户集体切换部门】用户关联旧部门不存在");
            throw new CzzException(ResultEnum.ILLEGAL_FAIL);
        }
        // 获取新部门对象，采取从映射中删除的方式，方便下面操作
        DeptEntity nextDept = deptMap.remove(deptUserFlowVo.getNextDeptId());
        if (Objects.isNull(nextDept)) {
            log.info("【部门用户集体切换部门】用户要关联的部门不存在");
            throw new CzzException(ResultEnum.REQUEST_FAIL);
        }

        /*
            获取部门关联角色
         */
        List<DeptRoleEntity> deptRoleList = deptRoleService.findList(new ArrayList<>(deptIdSet), null);
        // 按部门分组
        Map<Long, List<DeptRoleEntity>> deptRoleMap = deptRoleList.stream()
                .collect(Collectors.groupingBy(DeptRoleEntity::getDeptId));

        // 过滤禁用数据
        Predicate<DeptRoleEntity> statusFilter = deptRole ->
                CommonEnum.ZERO.getValue().equals(deptRole.getStatus());
        // 过滤领导专属数据
        Predicate<DeptRoleEntity> leaderFilter = deptRole ->
                CommonEnum.ONE.getValue().equals(deptRole.getUseLeader());

        // 获取新部门关联的角色列表
        deptRoleList = deptRoleMap.getOrDefault(deptUserFlowVo.getNextDeptId(), Collections.emptyList());
        // 映射待新增角色主键
        Set<Long> newRoleIdSet = deptRoleList.stream()
                // 只取可用数据
                .filter(statusFilter)
                // 只取非领导数据
                .filter(leaderFilter)
                .map(DeptRoleEntity::getRoleId)
                .collect(Collectors.toSet());

        // 追加待新增角色主键
        Stream.of(nextDept.getParentPath().split(Constant.SPLIT))
                .map(Long::valueOf)
                .filter(deptId -> !CommonEnum.ZERO.getLongValue().equals(deptId))
                .flatMap(deptId -> {
                    // 从映射中获取新部门的父级部门关联的角色列表映射
                    List<DeptRoleEntity> list = deptRoleMap.get(deptId);
                    if (CollectionUtils.isEmpty(list)) {
                        return Stream.empty();
                    }
                    return list.stream();
                })
                // 只取可用数据
                .filter(statusFilter)
                // 只取非领导数据
                .filter(leaderFilter)
                // 只取权限范围是所有子部门的数据
                .filter(deptRole -> CommonEnum.ONE.getValue().equals(deptRole.getUseRange()))
                .map(DeptRoleEntity::getRoleId)
                .forEach(newRoleIdSet::add);
        log.info("【部门用户集体切换部门】newRoleIdSet={}", newRoleIdSet);

        // 用户关联其他部门及其所有父级部门关联的角色集合，这部门数据不需要改变
        Set<Long> otherRoleIdSet = new HashSet<>();

        // 遍历用户剩余关联部门
        for (DeptEntity dept : deptMap.values()) {
            deptRoleList = deptRoleMap.get(dept.getId());
            if (!CollectionUtils.isEmpty(deptRoleList)) {
                // 添加
                otherRoleIdSet.addAll(CopyUtils.mapSet(deptRoleList, DeptRoleEntity::getRoleId));
            }
            // 追加
            Stream.of(dept.getParentPath().split(Constant.SPLIT))
                    .map(Long::valueOf)
                    .filter(id -> !CommonEnum.ZERO.getLongValue().equals(id))
                    .flatMap(deptId -> {
                        // 从映射中获取已关联部门的父级部门关联的角色列表
                        List<DeptRoleEntity> list = deptRoleMap.get(deptId);
                        if (CollectionUtils.isEmpty(list)) {
                            return Stream.empty();
                        }
                        return list.stream();
                    })
                    // 只取可用数据
                    .filter(statusFilter)
                    // 只取非领导数据
                    .filter(leaderFilter)
                    // 只取权限范围是所有子部门的数据
                    .filter(deptRole -> CommonEnum.ONE.getValue().equals(deptRole.getUseRange()))
                    .map(DeptRoleEntity::getRoleId)
                    .forEach(otherRoleIdSet::add);
        }
        log.info("【部门用户集体切换部门】otherRoleIdSet={}", otherRoleIdSet);

        /*
            获取用户关联角色
         */
        List<UserRoleEntity> userRoleList = userRoleService.findUserRoleList(userIdList, null,
                Collections.singletonList(RelationModeEnum.DEPT_ROLE.getValue()));
        // 分组
        Map<Long, List<UserRoleEntity>> userRoleMap = userRoleList.stream()
                .collect(Collectors.groupingBy(UserRoleEntity::getUserId));
        // 填充数据，确保每个用户都可以计算到
        for (Long userId : userIdList) {
            userRoleList = userRoleMap.get(userId);
            if (Objects.isNull(userRoleList)) {
                userRoleMap.put(userId, Collections.emptyList());
            }
        }

        List<UserRoleEntity> addUserRoleList = new ArrayList<>();
        List<UserRoleEntity> updateUserRoleList = new ArrayList<>();
        List<DeptUserEntity> updateDeptUserList = new ArrayList<>();

        for (Map.Entry<Long, List<UserRoleEntity>> entry : userRoleMap.entrySet()) {
            Long userId = entry.getKey();
            userRoleList = entry.getValue();

            TreeSet<Long> addSet = new TreeSet<>(newRoleIdSet);

            for (UserRoleEntity userRole : userRoleList) {
                if (otherRoleIdSet.contains(userRole.getRoleId())) {
                    /*
                        用户其他已关联部门，部门关联的角色包含遍历到的角色
                        其他已关联部门：
                            1、除preDeptId及其所有父级部门外的部门
                            2、除nextDeptId及其所有父级部门外的部门
                            3、剩余部门及其所有父级部，3涉及到的部门可能包含1和2里的部门，因为用户关联的部门可能是同一个父级部门下的子部门
                     */
                    log.info("【部门用户集体切换部门】用户其他已关联部门，部门关联的角色包含遍历到的角色。roleId={}", userRole.getRoleId());
                    continue;
                }
                if (addSet.remove(userRole.getRoleId())) {
                    log.info("【部门用户集体切换部门】用户新关联部门，部门关联的角色包含遍历到的角色。roleId={}", userRole.getRoleId());
                    continue;
                }

                UserRoleEntity updateUserRole = new UserRoleEntity();
                updateUserRole.setId(userRole.getId());
                if (!addSet.isEmpty()) {
                    /*
                        关联关系修改
                     */
                    Long roleId = addSet.pollFirst();

                    updateUserRole.setRoleId(roleId)
                            .setUpdateTime(date)
                            .setUpdateUser(userPo.getUsername())
                            .setUpdateUserId(userPo.getUserId());
                    updateUserRoleList.add(updateUserRole);
                } else {
                    // 删除关联关系
                    updateUserRole.setDeleteStatus(CommonEnum.ONE.getValue())
                            .setUpdateTime(date)
                            .setUpdateUser(userPo.getUsername())
                            .setUpdateUserId(userPo.getUserId());
                    updateUserRoleList.add(updateUserRole);
                }
            }
            // 迭代器剩余角色主键全部添加
            for (Long roleId : addSet) {
                if (otherRoleIdSet.contains(roleId)) {
                    // 逻辑同上面for
                    continue;
                }
                addUserRoleList.add(this.buildUserRole(userId, roleId, date, userPo));
            }

            List<Long> masterDeptIdList = masterDeptIdMap.getOrDefault(userId, Collections.emptyList());
            log.info("【部门用户集体切换部门】userId={} masterDeptIdList={}", userId, masterDeptIdList);
            boolean bool = masterDeptIdList.stream()
                    .map(deptMap::get)
                    .filter(Objects::nonNull)
                    .noneMatch(dept -> nextDept.getBusinessType().equals(dept.getBusinessType()));

            Integer masterStatus = bool ? CommonEnum.ZERO.getValue() : CommonEnum.ONE.getValue();

            // 为用户设置新部门
            DeptUserEntity updateDeptUser = updateDeptUserMap.get(userId);
            if (Objects.isNull(updateDeptUser)) {
                log.info("【部门用户集体切换部门】获取用户关联部门对象失败。userId={}", userId);
                throw new CzzException();
            }
            updateDeptUser.setDeptId(deptUserFlowVo.getNextDeptId())
                    .setMasterStatus(masterStatus)
                    .setLeaderStatus(CommonEnum.ONE.getValue())
                    .setUpdateTime(date)
                    .setUpdateUser(userPo.getUsername())
                    .setUpdateUserId(userPo.getUserId());
            updateDeptUserList.add(updateDeptUser);

        }

        // 用户切换部门流水映射
        List<DeptUserFlowEntity> userDeptFlowList = CopyUtils.mapList(userIdList, (userId) ->
                this.getUserDeptFlow(deptUserFlowVo, userId, userPo, date)
        );

        transactionService.execute(() -> {
            /*
                 修改部门关联用户
             */
            deptUserService.batchUpdate(updateDeptUserList);

            /*
                添加用户新关联角色
             */
            if (!addUserRoleList.isEmpty()) {
                userRoleService.batchSave(addUserRoleList);
            }

            /*
                修改用户关联角色
             */
            if (!updateUserRoleList.isEmpty()) {
                userRoleService.batchUpdate(updateUserRoleList);
            }

            /*
                批量保存用户切换部门流水
             */
            deptUserFlowService.batchSave(userDeptFlowList);

        });

        if (!addUserRoleList.isEmpty() || !updateUserRoleList.isEmpty()) {
            // 发送mq消息
            rabbitHelper.send(MqEnum.DEPT_USER, userIdList);
        }


        /*
            删除用户临时缓存
         */
        this.deleteUserCache(userIdList);
    }

    public void joinDept(DeptUserJoinVo deptUserJoinVo) {
        // 获取操作用户
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        List<Long> userIdList = Collections.singletonList(deptUserJoinVo.getUserId());

        /*
            获取用户已关联部门列表
         */
        List<DeptUserEntity> deptUserList = deptUserService.findList(null, userIdList);
        List<Long> deptIdList = new ArrayList<>();
        Set<Long> masterDeptIdSet = new HashSet<>();
        for (DeptUserEntity deptUser : deptUserList) {
            deptIdList.add(deptUser.getDeptId());
            if (CommonEnum.ZERO.getValue().equals(deptUser.getMasterStatus())) {
                masterDeptIdSet.add(deptUser.getDeptId());
            }
        }
        if (deptIdList.contains(deptUserJoinVo.getJoinDeptId())) {
            log.info("用户已在部门，无需重复加入");
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "用户已在选中部门中，无需重复加入");
        }
        deptIdList.add(deptUserJoinVo.getJoinDeptId());

        /*
            获取部门列表
         */
        List<DeptEntity> deptList = deptService.getList(deptIdList);

        DeptEntity joinDept = null;
        Set<Integer> masterBusinessTypeSet = new HashSet<>();
        for (DeptEntity dept : deptList) {
            if (dept.getId().equals(deptUserJoinVo.getJoinDeptId())) {
                joinDept = dept;
            }
            if (masterDeptIdSet.contains(dept.getId())) {
                masterBusinessTypeSet.add(dept.getBusinessType());
            }
        }
        if (Objects.isNull(joinDept)) {
            log.info("用户加入部门不存在");
            throw new CzzException(ResultEnum.NOT_FOUND);
        }

        Integer masterStatus = masterBusinessTypeSet.contains(joinDept.getBusinessType()) ?
                CommonEnum.ONE.getValue() : CommonEnum.ZERO.getValue();

        DeptUserEntity saveDeptUser = new DeptUserEntity();
        saveDeptUser.setUserId(deptUserJoinVo.getUserId())
                .setDeptId(deptUserJoinVo.getJoinDeptId())
                .setMasterStatus(masterStatus)
                .setLeaderStatus(CommonEnum.ONE.getValue())
                .setDeleteStatus(CommonEnum.ZERO.getValue())
                .setUpdateTime(date)
                .setUpdateUser(StringUtils.EMPTY)
                .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                .setCreateTime(date)
                .setCreateUser(userPo.getUsername())
                .setCreateUserId(userPo.getUserId());

        DeptUserFlowEntity deptUserFlow = new DeptUserFlowEntity();
        deptUserFlow.setUserId(deptUserJoinVo.getUserId())
                .setPreDeptId(CommonEnum.ZERO.getLongValue())
                .setNextDeptId(deptUserJoinVo.getJoinDeptId())
                .setMoveMode(DeptUserMoveModeEnum.JOIN.getValue())
                .setMoveRemark(StringUtils.EMPTY)
                .setDeleteStatus(CommonEnum.ZERO.getValue())
                .setUpdateTime(date)
                .setUpdateUser(StringUtils.EMPTY)
                .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                .setCreateTime(date)
                .setCreateUser(userPo.getUsername())
                .setCreateUserId(userPo.getUserId());

        /*
            获取部门关联角色数据
         */
        List<Set<Long>> setList = this.getDeptRole(null, deptUserJoinVo.getJoinDeptId());

        Set<Long> addRoleIdSet = setList.get(1);

        /*
            获取用户关联角色
         */
        List<UserRoleEntity> userRoleList =  userRoleService.findUserRoleList(userIdList, null,
                Collections.singletonList(RelationModeEnum.DEPT_ROLE.getValue()));
        Set<Long> roleIdSet = CopyUtils.mapSet(userRoleList, UserRoleEntity::getRoleId);

        List<UserRoleEntity> addUserRoleList = new ArrayList<>();
        for (Long roleId : addRoleIdSet) {
            if (roleIdSet.contains(roleId)) {
                log.info("用户已关联该角色。userId={} roleId={}", deptUserJoinVo.getJoinDeptId(), roleId);
                continue;
            }
            UserRoleEntity userRole = new UserRoleEntity();
            userRole.setUserId(deptUserJoinVo.getUserId())
                    .setRoleId(roleId)
                    .setRelationMode(RelationModeEnum.DEPT_ROLE.getValue())
                    .setDeleteStatus(CommonEnum.ZERO.getValue())
                    .setUpdateTime(date)
                    .setUpdateUser(StringUtils.EMPTY)
                    .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                    .setCreateTime(date)
                    .setCreateUser(userPo.getUsername())
                    .setCreateUserId(userPo.getUserId());
            addUserRoleList.add(userRole);
        }

        transactionService.execute(() -> {
            /*
                保存部门用户
             */
            deptUserService.saveOrEdit(saveDeptUser);

            /*
                保存部门用户流水
             */
            deptUserFlowService.saveOrEdit(deptUserFlow);

            /*
                添加用户新关联角色
             */
            if (!addUserRoleList.isEmpty()) {
                userRoleService.batchSave(addUserRoleList);
            }
        });

        if (!addUserRoleList.isEmpty()) {
            // 发送mq消息
            rabbitHelper.send(MqEnum.DEPT_USER, userIdList);
        }

        /*
            删除用户临时缓存
         */
        this.deleteUserCache(userIdList);
    }

    public void deleteUser(List<Long> userIdList) {
        // 获取正在删除用户的用户id
        Long optUserId = SecurityUtils.getUserId();

        if (userIdList.contains(optUserId)) {
            // 不允许自己删除自己
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "无法删除自己，请确认，如有问题，请联系管理员处理。");
        }

        /*
            删除用户
         */
        userService.delete(userIdList);

        // List转数组
        String[] userIds = new String[userIdList.size()];
        for (int i = 0; i < userIdList.size(); i++) {
            userIds[i] = userIdList.get(i).toString();
        }

        // 删除所有用户相关的临时缓存数据
        this.deleteUserCache(userIdList);
        // 删除Redis中保存的用户信息
        redisHashHandler.delete(CacheKeyUtils.getRedisHashKey(EntityConstant.USER), userIds);

        /*
            异步删除用户关联其他数据
         */
        asyncService.execute(() -> {
            // 异步删除用户关联角色数据
            userRoleService.deleteUserRole(userIdList, Collections.emptyList());

            // 异步删除用户关联部门
            deptUserService.deleteDeptUser(null, userIdList);

            // TODO 异步删除用户关联的博客数据
        });
    }

    public void deleteSelf() {
        // 获取操作用户
        UserPo userPo = SecurityUtils.getUser();

        String userId = userPo.getUserId().toString();

        /*
            删除用户
         */
        userService.delete(Collections.singletonList(userPo.getUserId()));

        // 删除所有用户相关的临时缓存数据
        this.deleteUserCache(Collections.singletonList(userPo.getUserId()));
        // 删除Redis中保存的用户信息
        redisHashHandler.delete(CacheKeyUtils.getRedisHashKey(EntityConstant.USER), userId);

        /*
            异步删除用户关联其他数据
         */
        asyncService.execute(() -> {
            // 异步删除用户关联角色数据
            userRoleService.deleteUserRole(Collections.singletonList(userPo.getUserId()), Collections.emptyList());

            // 异步删除用户关联部门
            deptUserService.deleteDeptUser(null, Collections.singletonList(userPo.getUserId()));

            // TODO 异步删除用户关联的博客数据
        });
    }

    public void deleteUserOnCache(List<String> userIdList) {
        // List 转 数组
        String[] userIds = userIdList.toArray(new String[0]);

        // 操作Redis缓存，批量删除用户缓存
        redisHashHandler.delete(CacheKeyUtils.getRedisHashKey(EntityConstant.USER), userIds);
    }

    public void clearUserCache() {
        // 删除用户缓存
        redisHandler.delete(CacheKeyUtils.getRedisHashKey(EntityConstant.USER));
    }

    /**
     * 分页获取用户
     * @param deptUserFormVo 参数对象
     * @return 用户分页数据
     */
    private PageDto<UserDto> getPageList(DeptUserFormVo deptUserFormVo) {
        String userListKey = deptUserFormVo.getUserListKey();
        // 查询Redis缓存，获取用户分页数据列表
        PageDto<UserDto> pageDto = redisStringHandler.get(userListKey);
        if (pageDto != null) {
            log.info("redis缓存获取用户分页数据");
            throttleHandler.throttleRun(() -> {
                // 尝试更新缓存键的过期时间
                redisHandler.tryUpdateKeyExpire(userListKey, 150, RandomNumUtils.random5Minutes(10));
            }, userListKey, 1500, TimeUnit.MILLISECONDS);
            return pageDto;
        }
        // 获取Redis分布式锁对象
        RLock lock = redissonClient.getLock(RedisConstant.LOCK + userListKey);
        // 加锁
        lock.lock();

        try {
            // 重复查询Redis缓存，获取用户分页数据列表
            pageDto = redisStringHandler.get(userListKey);
            if (pageDto != null) {
                log.info("double check redis缓存获取用户分页数据");
                return pageDto;
            }

            /*
                分页获取用户
             */
            PageDto<UserEntity> userPageDto = userService.getPageList(deptUserFormVo);
            if (userPageDto.isEmpty()) {
                pageDto = userPageDto.rebuild();
                // 缓存检索结果
                redisStringHandler.set(userListKey, pageDto, RandomNumUtils.random5Minutes(10), TimeUnit.SECONDS);
                return pageDto;
            }

            List<UserEntity> userList = userPageDto.getList();
            List<Long> userIdList = CopyUtils.mapList(userList, UserEntity::getUserId);

            /*
                获取用户关联部门
             */
            List<DeptUserEntity> deptUserList = deptUserService.findList(null, userIdList);

            List<Long> deptIdList = new ArrayList<>();
            Map<Long, List<Long>> deptUserMap = new HashMap<>();
            Map<Long, List<Integer>> deptUserLeaderStatusMap = new HashMap<>();
            for (DeptUserEntity deptUser : deptUserList) {
                deptIdList.add(deptUser.getDeptId());
                List<Long> idList = deptUserMap.computeIfAbsent(deptUser.getUserId(), k -> new ArrayList<>());
                idList.add(deptUser.getDeptId());

                List<Integer> leaderStatusList = deptUserLeaderStatusMap.computeIfAbsent(deptUser.getUserId(),
                        k -> new ArrayList<>());
                leaderStatusList.add(deptUser.getLeaderStatus());
            }

            /*
                获取部门名称映射
             */
            Map<Long, String> deptNameMap = deptService.getDeptNameMap(deptIdList, Function.identity());


            // 列表映射
            List<UserDto> userDtoList = CopyUtils.mapList(userList, user -> {
                // 用户映射
                UserDto userDto = CopyUtils.map(user, UserDto.class);

                StringBuilder sb = new StringBuilder();

                List<Long> _deptIdList = deptUserMap.getOrDefault(user.getUserId(), Collections.emptyList());
                for (Long deptId : _deptIdList) {
                    String deptName = deptNameMap.get(deptId);
                    if (StringUtils.isNotBlank(deptName)) {
                        sb.append(deptName).append('、');
                    }
                }
                if (sb.length() > 0) {
                    sb.deleteCharAt(sb.length() - 1);
                }
                userDto.setDeptNames(sb.toString());

                if (StringUtils.isNotBlank(user.getPhone())) {
                    // 手机号解密
                    String decodePhone = aesService.decodeHex(user.getPhone());
                    // 手机号半解密
                    String subDecodePhone = DataUtils.dataMask(decodePhone);

                    userDto.setDecodePhone(decodePhone)
                            .setSubDecodePhone(subDecodePhone);
                }
                if (StringUtils.isNotBlank(user.getEmail())) {
                    // 邮箱号解密
                    String decodeEmail = aesService.decodeHex(user.getEmail());
                    // 邮箱号半解密
                    String subDecodeEmail = DataUtils.dataMask(decodeEmail, 1, 6);

                    userDto.setDecodeEmail(decodeEmail)
                            .setSubDecodeEmail(subDecodeEmail);
                }

                // 判断用户是否是某个部门的领导
                boolean bool = deptUserLeaderStatusMap.getOrDefault(user.getUserId(), Collections.emptyList())
                        .stream()
                        .anyMatch(leaderStatus -> CommonEnum.ZERO.getValue().equals(leaderStatus));

                userDto.setStatusName(CommonEnum.getStatusName(user.getStatus()))
                        .setLeaderStatusName(bool ? "是" : "否");

                return userDto;
            });

            // 数据封装返回
            pageDto = userPageDto.rebuild(userDtoList);

            // 缓存检索结果
            redisStringHandler.set(userListKey, pageDto, RandomNumUtils.random5Minutes(10), TimeUnit.SECONDS);

            return pageDto;
        } finally {
            // 判断当前锁对象是否还持有锁 并 持有该锁的线程与当前业务线程一致
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                // 解锁
                lock.unlock();
            }
        }
    }

    /**
     * 删除所有用户相关的临时缓存
     */
    private void deleteUserCache(List<Long> userIdList) {
        List<String> patternKeyList = CopyUtils.mapList(userIdList, userId ->
                RedisConstant.STRING + Constant.SECURITY_USER + Constant.SPLIT + userId + Constant.SPLIT
                        + RedisConstant.ASTERISK);
        patternKeyList.add(RedisConstant.STRING + EntityConstant.USER + Constant.UNDER + RedisConstant.LIST
                + RedisConstant.ASTERISK);
        redisHandler.fuzzyDelete(patternKeyList);
    }

    /**
     * 获取用户切换部门流水对象
     * @param deptUserFlowVo 用户切换部门参数对象
     * @param userId         用户主键
     * @param userPo         操作用户
     * @param date           日期对象
     * @return 用户切换部门流水对象
     */
    private DeptUserFlowEntity getUserDeptFlow(DeptUserFlowVo deptUserFlowVo, Long userId, UserPo userPo, Date date) {
        DeptUserFlowEntity userDeptFlow = CopyUtils.map(deptUserFlowVo, DeptUserFlowEntity.class);
        userDeptFlow.setId(null)
                .setUserId(userId)
                .setDeleteStatus(CommonEnum.ZERO.getValue())
                .setUpdateTime(date)
                .setUpdateUser(StringUtils.EMPTY)
                .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                .setCreateTime(date)
                .setCreateUser(userPo.getUsername())
                .setCreateUserId(userPo.getUserId());
        return userDeptFlow;
    }

    /**
     * 获取部门关联角色数据
     * 1、用户已通过部门关联的角色主键集合
     * 2、用户即将通过部门关联的角色主键集合
     * @param preDeptId  原所属部门主键
     * @param nextDeptId 新所属部门主键
     * @return 封装数据的对象数组
     */
    private List<Set<Long>> getDeptRole(Long preDeptId, Long nextDeptId) {

        Set<Long> roleIdSet = Collections.emptySet();
        if (Objects.nonNull(preDeptId)) {
            /*
                获取父级部门
             */
            List<Long> deptIdList = deptService.findParentIdList(preDeptId);
            deptIdList.add(preDeptId);

            /*
                获取部门关联角色
             */
            List<DeptRoleEntity> deptRoleList = deptRoleService.findDeptRoleList(deptIdList);
            // 收集id
            roleIdSet = CopyUtils.mapSet(deptRoleList, DeptRoleEntity::getRoleId);
        }
        log.info("原所属部门及其所有父级部门关联的角色：{}", roleIdSet);

        Set<Long> addRoleIdSet = new HashSet<>();
        if (Objects.nonNull(nextDeptId)) {
            /*
                获取父级部门
             */
            List<Long> deptIdList = deptService.findParentIdList(nextDeptId);
            deptIdList.add(nextDeptId);

            /*
                获取部门关联角色
             */
            List<DeptRoleEntity> deptRoleList = deptRoleService.findDeptRoleList(deptIdList);


            for (DeptRoleEntity deptRole : deptRoleList) {
                if (CommonEnum.ZERO.getValue().equals(deptRole.getUseLeader())) {
                    log.debug("部门关联角色为领导专属。id={}", deptRole.getId());
                    continue;
                }
                if (CommonEnum.ONE.getValue().equals(deptRole.getStatus())) {
                    log.debug("部门关联角色状态不满足条件。id={} status={}", deptRole.getId(),
                            CommonEnum.getStatusName(deptRole.getStatus()));
                    continue;
                }
                if (CommonEnum.ONE.getValue().equals(deptRole.getUseRange())) {
                    log.debug("部门关联角色使用范围为本部门及其所有子孙部门。id={}", deptRole.getId());
                    addRoleIdSet.add(deptRole.getRoleId());
                    continue;
                }
                if (nextDeptId.equals(deptRole.getDeptId())) {
                    log.debug("新所属部门关联角色。id={} roleId={}", deptRole.getId(), deptRole.getRoleId());
                    addRoleIdSet.add(deptRole.getRoleId());
                }
            }
        }
        log.info("新所属部门及其所有父级部门关联的角色：{}", addRoleIdSet);

        return Arrays.asList(roleIdSet, addRoleIdSet);
    }

    /**
     * 构造用户关联角色对象
     * @param userId 用户主键
     * @param roleId 角色主键
     * @param date   日期对象
     * @param userPo 操作用户
     * @return 用户关联角色对象
     */
    private UserRoleEntity buildUserRole(Long userId, Long roleId, Date date, UserPo userPo) {
        UserRoleEntity userRole = new UserRoleEntity();
        userRole.setUserId(userId)
                .setRoleId(roleId)
                .setRelationMode(RelationModeEnum.DEPT_ROLE.getValue())
                .setDeleteStatus(CommonEnum.ZERO.getValue())
                .setUpdateTime(date)
                .setUpdateUser(StringUtils.EMPTY)
                .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                .setCreateTime(date)
                .setCreateUser(userPo.getUsername())
                .setCreateUserId(userPo.getUserId());
        return userRole;
    }
}
